Проектная работа по анализу рынка заведений общественного питания Москвы¶
ОГЛАВЛЕНИЕ:
Обзор данных - загрузка данных и ознакомление с общей информацией.
Предобработка данных - необходимо провести необходимую предобработку:
Исследовательский анализ данных:
- Категории заведений.
- Количества посадочных мест.
- Сетевых и несетевых заведений.
- Анализ топ-15 сетевых заведений.
- Количество заведений по административным районам.
- Рейтинг заведений.
- Карта заведений по Москве
- Топ-15 улиц по количеству заведений
- Улицы с 1 заведением
- Ценовой диапазон.
- Круглосуточные заведения.
- Заведения с низкими рейтингами.
- Вывод
ПРЕЗЕНТАЦИЯ: https://disk.yandex.ru/d/d-u1ec5Dap5lWQ
Описание проекта:¶
Инвесторы из фонда «Shut Up and Take My Money» решили попробовать себя в новой области и открыть заведение общественного питания в Москве. Заказчики ещё не знают, что это будет за место: кафе, ресторан, пиццерия, паб или бар, — и какими будут расположение, меню и цены. Необходимо провести анализ рынка заведений общественного питания Москвы, для дальнейшего принятия решения в выборе подходящего инвесторам места.
Цель исследования:
Провести исследование рынка заведений общественного питания Москвы и найти интересные особенности.
Провести детализированное исследование: открытие кофейни.
Для решения поставленной цели определим этапы исследования.
Ход исследования:
Загрузка данных и ознакомление с общей информацией.
Предобработка данных - необходимо провести необходимую предобработку (дубликаты, пропуски, дополнительные столбцы).
Исследовательский анализ данных. Провести анализ показателей:
- Категории заведений.
- Количества посадочных мест.
- Сетевых и несетевых заведений.
- Названия заведений.
- Количество заведений по административным районам.
- Рейтинг заведений.
- Карта заведений по Москве
- Топ-15 улиц по количеству заведений
- Улицы с 1 заведением
- Ценовой диапазон.
- Круглосуточные заведения.
- Заведения с низкими рейтингами.
Детлизированное исследование: открытие кофейни. Исследовать:
- Количество и расположение кофейн
- Время работы кофейн
- Рейтинги кофейн и их распределение по районам
- Цены
Подвести итоги и написать рекомендации
Для проведения исследования доступен файл с заведениями общественного питания Москвы, составленный на основе данных сервисов Яндекс Карты и Яндекс Бизнес на лето 2022 года, который содержит следующую информацию:
- название заведения;
- адрес заведения;
- категория заведения, например «кафе», «пиццерия» или «кофейня»;
- информация о днях и часах работы;
- широта географической точки, в которой находится заведение;
- долгота географической точки, в которой находится заведение;
- рейтинг заведения по оценкам пользователей в Яндекс Картах (высшая оценка — 5.0);
- категория цен в заведении, например «средние», «ниже среднего», «выше среднего» и так далее;
- строка, которая хранит среднюю стоимость заказа в виде диапазона
- число с оценкой среднего чека, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Средний счёт»
- число с оценкой одной чашки капучино, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Цена одной чашки капучино»
- число, выраженное 0 или 1, которое показывает, является ли заведение сетевым (для маленьких сетей могут встречаться ошибки)
- административный район, в котором находится заведение, например Центральный административный округ;
- количество посадочных мест.
Информация, размещённая в сервисе Яндекс Бизнес, могла быть добавлена пользователями или найдена в общедоступных источниках. Она носит исключительно справочный характер.
Шаг 1. Загрузка данных и обзор информации¶
Загруим необходимые библиотеки и код игнорирования сообщений предупреждений
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import folium
import json
from plotly import graph_objects as go
from folium import Map, Choropleth
from folium import Map, Marker
from folium.plugins import MarkerCluster
from folium.features import CustomIcon
import re
import warnings; warnings.filterwarnings(action='ignore')
/Users/mariapolivanova/anaconda3/envs/practicum/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.17.3 and <1.25.0 is required for this version of SciPy (detected version 1.26.4
warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
Откроем файл с данными
#считываем информацию и сохраняем в датафреймы
try:
df = pd.read_csv(' .csv')
except FileNotFoundError:
df = pd.read_csv(' .csv')
Датафрейм содержит большое количество данных, для вывода всех столбцов снимим ограничение на вывод
# снимаем ограничение на количество столбцов
pd.set_option('display.max_columns', None)
# снимаем ограничение на ширину столбцов
pd.set_option('display.max_colwidth', None)
Для ознокомления с данными посмотрим общую информацию, первые строки датафрейма, на распределение значений в данных, наличие пропущенных значений и явных дубликатов.
#Зададим функцию для просмотра общей информации, первых строк датафрейма,
#на распределение значений в данных, наличие пропущенных значений и явных дубликатов
def general_info(dataframe):
return display(
dataframe.info(),
'*'*50,
dataframe.describe(),
'*'*50,
dataframe.head(5),
'*'*50,
'Пропущенные значения среди данных:', dataframe.isna().sum(),
'*'*50,
'Дубликатов среди данных:', dataframe.duplicated().sum()
)
#посмотрим в разрезе заданной функции на данные moscow_places.csv
general_info(df)
<class 'pandas.core.frame.DataFrame'> RangeIndex: 8406 entries, 0 to 8405 Data columns (total 14 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 8406 non-null object 1 category 8406 non-null object 2 address 8406 non-null object 3 district 8406 non-null object 4 hours 7870 non-null object 5 lat 8406 non-null float64 6 lng 8406 non-null float64 7 rating 8406 non-null float64 8 price 3315 non-null object 9 avg_bill 3816 non-null object 10 middle_avg_bill 3149 non-null float64 11 middle_coffee_cup 535 non-null float64 12 chain 8406 non-null int64 13 seats 4795 non-null float64 dtypes: float64(6), int64(1), object(7) memory usage: 919.5+ KB
None
'**************************************************'
| lat | lng | rating | middle_avg_bill | middle_coffee_cup | chain | seats | |
|---|---|---|---|---|---|---|---|
| count | 8406.000000 | 8406.000000 | 8406.000000 | 3149.000000 | 535.000000 | 8406.000000 | 4795.000000 |
| mean | 55.750109 | 37.608570 | 4.229895 | 958.053668 | 174.721495 | 0.381275 | 108.421689 |
| std | 0.069658 | 0.098597 | 0.470348 | 1009.732845 | 88.951103 | 0.485729 | 122.833396 |
| min | 55.573942 | 37.355651 | 1.000000 | 0.000000 | 60.000000 | 0.000000 | 0.000000 |
| 25% | 55.705155 | 37.538583 | 4.100000 | 375.000000 | 124.500000 | 0.000000 | 40.000000 |
| 50% | 55.753425 | 37.605246 | 4.300000 | 750.000000 | 169.000000 | 0.000000 | 75.000000 |
| 75% | 55.795041 | 37.664792 | 4.400000 | 1250.000000 | 225.000000 | 1.000000 | 140.000000 |
| max | 55.928943 | 37.874466 | 5.000000 | 35000.000000 | 1568.000000 | 1.000000 | 1288.000000 |
'**************************************************'
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | WoWфли | кафе | Москва, улица Дыбенко, 7/1 | Северный административный округ | ежедневно, 10:00–22:00 | 55.878494 | 37.478860 | 5.0 | NaN | NaN | NaN | NaN | 0 | NaN |
| 1 | Четыре комнаты | ресторан | Москва, улица Дыбенко, 36, корп. 1 | Северный административный округ | ежедневно, 10:00–22:00 | 55.875801 | 37.484479 | 4.5 | выше среднего | Средний счёт:1500–1600 ₽ | 1550.0 | NaN | 0 | 4.0 |
| 2 | Хазри | кафе | Москва, Клязьминская улица, 15 | Северный административный округ | пн-чт 11:00–02:00; пт,сб 11:00–05:00; вс 11:00–02:00 | 55.889146 | 37.525901 | 4.6 | средние | Средний счёт:от 1000 ₽ | 1000.0 | NaN | 0 | 45.0 |
| 3 | Dormouse Coffee Shop | кофейня | Москва, улица Маршала Федоренко, 12 | Северный административный округ | ежедневно, 09:00–22:00 | 55.881608 | 37.488860 | 5.0 | NaN | Цена чашки капучино:155–185 ₽ | NaN | 170.0 | 0 | NaN |
| 4 | Иль Марко | пиццерия | Москва, Правобережная улица, 1Б | Северный административный округ | ежедневно, 10:00–22:00 | 55.881166 | 37.449357 | 5.0 | средние | Средний счёт:400–600 ₽ | 500.0 | NaN | 1 | 148.0 |
'**************************************************'
'Пропущенные значения среди данных:'
name 0 category 0 address 0 district 0 hours 536 lat 0 lng 0 rating 0 price 5091 avg_bill 4590 middle_avg_bill 5257 middle_coffee_cup 7871 chain 0 seats 3611 dtype: int64
'**************************************************'
'Дубликатов среди данных:'
0
В полученном датафрейме:
- 14 столбцов, наименования приведены к змеиному регистру
- 8 406 заведений;
- явных дубликатов не выявлено, стоит проверить на неявные дубликаты;
- типы данных: float64, int64, object;
- рейтин по 5-ти бальной шкале, аномалий не выявлено - минимальное значение - 1, максимальное - 5;
- посадочных мест от 0 до 1288;
- пропущенные значения в данных:
hours- 536price- 5091avg_bill- 4590middle_avg_bill- 5257middle_coffee_cup- 7871seats- 3611
- проверить временной промежуток за который предоставлены данные нет возможности.
Вернуться в начало проекта
Шаг 2. Предобработка данных¶
Проверка наличия и обработка дубликатов¶
# Для сравнения сколько данных останется после предобработки
#выведем сумму заведений до предобработки
before_processing = df['name'].count()
print(
'Количество заведений в датафрейме до предобработки:',
before_processing
)
Количество заведений в датафрейме до предобработки: 8406
# посмотрим на уникальные значения по разным столбцам,
# где могут быть неявные дубликаты.
print('Уникальные названия категорий зааведений:')
print(df['category'].unique())
print('_'*80)
print('Уникальные значения времени работы:')
print(df['hours'].unique())
print('_'*80)
print('Уникальные категории сетевых/несетевых заведений:')
print(df['chain'].unique())
print('_'*80)
print('Уникальные наименования административных районов Москвы:')
print(df['district'].unique())
Уникальные названия категорий зааведений: ['кафе' 'ресторан' 'кофейня' 'пиццерия' 'бар,паб' 'быстрое питание' 'булочная' 'столовая'] ________________________________________________________________________________ Уникальные значения времени работы: ['ежедневно, 10:00–22:00' 'пн-чт 11:00–02:00; пт,сб 11:00–05:00; вс 11:00–02:00' 'ежедневно, 09:00–22:00' ... 'пн-пт 08:30–21:30; сб,вс 09:00–21:30' 'пн-чт 13:00–22:00; пт,сб 13:00–22:30; вс 13:00–22:00' 'пн-сб 10:30–21:30'] ________________________________________________________________________________ Уникальные категории сетевых/несетевых заведений: [0 1] ________________________________________________________________________________ Уникальные наименования административных районов Москвы: ['Северный административный округ' 'Северо-Восточный административный округ' 'Северо-Западный административный округ' 'Западный административный округ' 'Центральный административный округ' 'Восточный административный округ' 'Юго-Восточный административный округ' 'Южный административный округ' 'Юго-Западный административный округ']
Среди категорий заведений, сетевых/несетевых категорий, и наименований административных районов дубликатов не обнаружено.
Среди значений времени работы заведений слишком разнообразные значения, их трудно исследовать на дубликаты, но это не так и важно.
Посмотрим наличие дубликатов среди наименований заведений.
print(
'Количество уникальных названий заведений:',
df.name.nunique()
)
Количество уникальных названий заведений: 5614
#Посмотрим наличие дубликатов среди наименований заведений.
print(
'Всего дубликатов среди наименований заведений',
df['name'].duplicated().sum()
)
Всего дубликатов среди наименований заведений 2792
#sorted(df['name'].unique())
Нормальное явление что среди наименований есть дубликаты, так как среди заведений есть сетевые, которые имеют одинаковое название. Приведем все наименования заведений и адреса к нижнему регистру, и проверим на дубликаты среди названий и адресов одновременно.
#Приведем все наименования заведений и адреса к нижнему регистру
df['name'] = df['name'].str.lower()
df['address'] = df['address'].str.lower()
print(
'Дубликатов по наименованию и географическому местоположению:',
df.duplicated(
subset=['name', 'address', 'lat', 'lng', 'category']
).sum()
)
Дубликатов по наименованию и географическому местоположению: 1
Выявлено 1 неявный дубликат заведения с одинаковыми наименованими, адресами, категорей, широтой и долготой географической точки. Такие дубликаты стоит удалить.
#посмотрим на строки с неявными дубликатами
df[df[['name', 'address', 'lat', 'lng', 'category']].duplicated(
keep=False
)]
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1430 | more poke | ресторан | москва, волоколамское шоссе, 11, стр. 2 | Северный административный округ | ежедневно, 09:00–21:00 | 55.806307 | 37.497566 | 4.2 | NaN | NaN | NaN | NaN | 0 | 188.0 |
| 1511 | more poke | ресторан | москва, волоколамское шоссе, 11, стр. 2 | Северный административный округ | пн-чт 09:00–18:00; пт,сб 09:00–21:00; вс 09:00–18:00 | 55.806307 | 37.497566 | 4.2 | NaN | NaN | NaN | NaN | 1 | 188.0 |
#удалим найденный дубликат
df = df.drop_duplicates(
subset = ['name', 'address', 'lat', 'lng', 'category'],
keep = 'first'
).reset_index(drop=True)
#посмотрим на строки с неявными дубликатами в случае разности в наименовании
#df[df[['address', 'lat', 'lng', 'category']].duplicated(keep=False)]
Выявлены заведения с одинаковым адресом, географическим положением и категорией и схожие по названию но разные по написанию:
- "кафе-кулинария сикварули" / "сикварули";
- "dragon bubble tea" / "dragon mixology bar";
- "леон" / "leon".
Это дубликаты, их нужно удалить.
# приведем наименования дубликатов к единому названию и удалим их
df['name'] =df['name'].str.replace('кафе-кулинария сикварули', 'сикварули')
df['name'] =df['name'].str.replace('dragon bubble tea', 'dragon mixology bar')
df['name'] =df['name'].str.replace('леон', 'leon')
#удалим найденный дубликат
df = df.drop_duplicates(
subset = ['name', 'address', 'lat', 'lng', 'category'],
keep = 'first'
).reset_index(drop=True)
# Уберем из названий заведений верхний литерал "'"
df['name'] = df['name'].str.replace("'", '')
# Посмотрим сколько осталось уникальных наименований заведений после предобработки
print('Количество уникальных занчений "name":', df['name'].unique().shape[0])
Количество уникальных занчений "name": 5508
До предобработки было 5614 уникикальных наименования, после предобработки стало 5508. Дубликаты были удалены. Перейдем к изучению пропусков.
Обработка пропусков¶
Как было выявлено на этапе ознакомления с датафреймом встречаются строки с пропущенными значениями по некоторым данным.
hours(время работы заведения) - 536;price(категория цен) - 5091;avg_bill(средняя стоимость заказа) - 4590;middle_avg_bill(число с оценкой среднего чека) - 5257;middle_coffee_cup(число с оценкой одной чашки капучино) - 7871;seats(количество посадочных мест) - 3611;
Посмотрим какую долю составляют пропуски.
print('Доля пропусков по отношению к общему числу данных:')
display(pd.DataFrame(round(df.isna().mean().sort_values()*100,)))
Доля пропусков по отношению к общему числу данных:
| 0 | |
|---|---|
| name | 0.0 |
| category | 0.0 |
| address | 0.0 |
| district | 0.0 |
| lat | 0.0 |
| lng | 0.0 |
| rating | 0.0 |
| chain | 0.0 |
| hours | 6.0 |
| seats | 43.0 |
| avg_bill | 55.0 |
| price | 61.0 |
| middle_avg_bill | 63.0 |
| middle_coffee_cup | 94.0 |
Слишком большая доля пропущенных значений, если их заполнять медианой, то такое большое количество может сильно исказить данные и повлиять на ход исследование, поэтому их стоит оставить без изменения. И продолжить работу с теми данными что есть.
Создадим дополнительные столбцы¶
Создадим столбец street с названиями улиц из столбца с адресом.
words = ['проезд','шоссе','улица','переулок','микрорайон','мкад','проспект','пр.',
'площадь','аллея','бульвар','набережная','сквер','тупик','линия','территория',
'квартал','просек','парк','мост']
str_pat = r".*,\s*\b([^,]*?(?:{})\b[^,]*)[,$]+".format("|".join(words))
df['street'] = df['address'].str.extract(str_pat, flags=re.I)
Добавим столбец is_24/7 с обозначением, что заведение работает ежедневно и круглосуточно (24/7):
- логическое значение
True— если заведение работает ежедневно и круглосуточно; - логическое значение
False— в противоположном случае.
def is_24_7(time):
if time == 'ежедневно, круглосуточно':
return True
else:
return False
df['is_24_7'] = df['hours'].apply(is_24_7)
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 8402 entries, 0 to 8401 Data columns (total 16 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 8402 non-null object 1 category 8402 non-null object 2 address 8402 non-null object 3 district 8402 non-null object 4 hours 7866 non-null object 5 lat 8402 non-null float64 6 lng 8402 non-null float64 7 rating 8402 non-null float64 8 price 3315 non-null object 9 avg_bill 3816 non-null object 10 middle_avg_bill 3149 non-null float64 11 middle_coffee_cup 535 non-null float64 12 chain 8402 non-null int64 13 seats 4793 non-null float64 14 street 8267 non-null object 15 is_24_7 8402 non-null bool dtypes: bool(1), float64(6), int64(1), object(8) memory usage: 992.9+ KB
На этапе предобработки данных:
- Выявлен и удален 1 неявный дубликат - заведения с одинаковыми наименованими, адресами, категорей, широтой и долготой географической точки.
- По пропускам - принято решение оставить как есть, так как удаление или заполнение медианным значением такого большого количества данных может исказить ход исследования.
- добавлены столбец с данными о наименовании улицы и столбец с обозначением работы в ежеднемном и круглосуточном режиме или нет.
Вернуться в начало проекта
Обработка аномалий и редких значений.¶
df.describe()
| lat | lng | rating | middle_avg_bill | middle_coffee_cup | chain | seats | |
|---|---|---|---|---|---|---|---|
| count | 8402.000000 | 8402.000000 | 8402.000000 | 3149.000000 | 535.000000 | 8402.000000 | 4793.000000 |
| mean | 55.750090 | 37.608550 | 4.229910 | 958.053668 | 174.721495 | 0.381219 | 108.425621 |
| std | 0.069667 | 0.098565 | 0.470429 | 1009.732845 | 88.951103 | 0.485715 | 122.845421 |
| min | 55.573942 | 37.355651 | 1.000000 | 0.000000 | 60.000000 | 0.000000 | 0.000000 |
| 25% | 55.704950 | 37.538632 | 4.100000 | 375.000000 | 124.500000 | 0.000000 | 40.000000 |
| 50% | 55.753384 | 37.605246 | 4.300000 | 750.000000 | 169.000000 | 0.000000 | 75.000000 |
| 75% | 55.795030 | 37.664780 | 4.400000 | 1250.000000 | 225.000000 | 1.000000 | 140.000000 |
| max | 55.928943 | 37.874466 | 5.000000 | 35000.000000 | 1568.000000 | 1.000000 | 1288.000000 |
Есть значения которые сильно выбиваются от медианных по трем столбцам:
middle_avg_bill;middle_coffee_cup;seats.
Стоит разобраться с выбросами и аномалиями по этим столбцам.
sns.set_style('darkgrid')
plt.figure(figsize=(15, 7))
sns.boxplot(x = 'middle_avg_bill', data = df)
plt.title('Ящик с усами по показателю среднего чека заведений Москвы')
plt.xlabel('Сумма среднего чека, руб.')
plt.ylabel('Показатель среднего чека')
plt.show();
# Посмотрим на данные этих заведений со средним чеком более 10 000руб.
df.query('middle_avg_bill >= 10000')
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | street | is_24_7 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 730 | чойхона | бар,паб | москва, дмитровское шоссе, 95а | Северный административный округ | ежедневно, 10:00–23:00 | 55.871497 | 37.543555 | 4.4 | высокие | Средний счёт:5000–17000 ₽ | 11000.0 | NaN | 0 | 49.0 | дмитровское шоссе | False |
| 5477 | гости | ресторан | москва, шоссе энтузиастов, 52 | Восточный административный округ | пн,вс 18:00–22:30 | 55.759088 | 37.760570 | 4.1 | высокие | Средний счёт:5000–15000 ₽ | 10000.0 | NaN | 0 | NaN | шоссе энтузиастов | False |
| 7173 | кафе | ресторан | москва, каширское шоссе, 23, стр. 2 | Южный административный округ | ежедневно, круглосуточно | 55.657450 | 37.646665 | 4.1 | высокие | Средний счёт:20000–50000 ₽ | 35000.0 | NaN | 0 | 100.0 | каширское шоссе | True |
Наименование заведения "Кафе", категория - ресторан, адрес - Москва, Каширское шоссе, 23, стр. 2, находится в здании НМИЦ онкологии им. Н. Н. Блохина Минздрава России, цены не характерные для заведений общественного питания медицинских учреждений, больше похоже на стоимость исследований в этом НМИЦ.
Аномальных значения 3 (около 0.03% от всех данных), их можно смело удалять.
# Удалим заведения с аномальным средним чеком свыше 10 000 руб.
df.drop(index=df.query('middle_avg_bill >= 10000').index,inplace=True)
# Построим ящик с усами для выявления аномальных значений
#по средней стоимости чашки капучино
plt.figure(figsize=(15, 7))
sns.boxplot(x = 'middle_coffee_cup', data = df)
plt.title('Ящик с усами по показателю стоимости чашки капучино заведений Москвы')
plt.xlabel('Сумма, руб.')
plt.ylabel('Показатель стоимости чашки капучино')
plt.show();
# Посмотрим на данные заведения в таблице со значением за чашку капучино более 400 руб.
df.query('middle_coffee_cup >= 400')
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | street | is_24_7 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2857 | шоколадница | кофейня | москва, большая семёновская улица, 27, корп. 1 | Восточный административный округ | ежедневно, 08:00–23:00 | 55.782268 | 37.709022 | 4.2 | средние | Цена чашки капучино:230–2907 ₽ | NaN | 1568.0 | 1 | 48.0 | большая семёновская улица | False |
Вероятнее всего это опечатка, в меню данного заведения на сайте указаны цены на кофе от 90 до максимум 290 руб. Стоит исправить эту ошибку на среднее значение - 260.0 руб.
df = df.apply(lambda x: x.replace(
{'Цена чашки капучино:230–2907 ₽':'Цена чашки капучино:230–290 ₽'},
regex=True
))
df['middle_coffee_cup'] = df['middle_coffee_cup'].replace(1568.0, 260.0)
Теперь посмотрим на ящик с усами по показателю - посадочные места.
# Построим боксплот для показателя количество посадочных мест
plt.figure(figsize=(15, 7))
sns.boxplot(x = 'seats', data = df)
plt.title('Ящик с усами по количеству посадочных мест заведений Москвы')
plt.xlabel('Количество посадочных мест, шт.')
plt.ylabel('Показатель посадки')
plt.show();
# Загрузим данные заведений с посадкой свыше 1200 мест
#display(df.query('seats > 1200'))
Всего 11 заведений с самой большой посадкой 1288 человек и все они находятся в Западном административном округе Москвы на проспекте Вернадского, при том что имеют разные географические координаты расположения.
Встречаются категории - 4 ресторана, 2 кафе, 2 кофейни, что очень удивительно, обычно кофейни не отличаются высокой посадкой, 2 бара,паба и 1 пиццерия. Предпологается что это заведения с банкетными залами, либо с ресторанными двориками в ТЦ где большая посадка, так же, например, по адресу проспект Вернадского 84 стр. 1 находится филиал РАНХиГС -высшее учебное заведение, скорее всего со столовой, что тоже может давать большую посадку (3 заведения с максимальной посадкой находятся по этому адресу.) Эти заведения выбросы.
Посмотрим какое количество посадочных мест превышает 99 процентилей.
Рассчитаем 99-й перцентиль количества посадочных мест всего по всем заведениям.
# сделаем срез - таблицу без пропущенных значений для оценки 99 перцентиля
df_seats_not_nan = df
df_seats_not_nan['seats'] = df_seats_not_nan['seats'].fillna(0)
print(np.percentile(df_seats_not_nan['seats'], 99))
491.0
Среди заведений с указанным количеством посадочных мест, 1% заведений имеет более 490 посадочных мест, остальные данные , менее 1 % - аномалии, их стоит убрать из расчета.
# Избавимся от аномальных значений свыше 490 посадочных мест
df = df.query('seats < 490')
# Для сравнения сколько данных осталось после предобработки
#выведем количество и долю заведений
after_processing = df['name'].count()
print('Количество заведений в датафрейме после предобработки:', after_processing)
print(
'Доля удаленных заведений после предобработки:',
round((before_processing - after_processing)*100/before_processing, 1), '%')
Количество заведений в датафрейме после предобработки: 8314 Доля удаленных заведений после предобработки: 1.1 %
Аномальные значения составили 1.1%, были удалены. Приступим к дальнейшему анализу данных.
df.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 8314 entries, 0 to 8401 Data columns (total 16 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 8314 non-null object 1 category 8314 non-null object 2 address 8314 non-null object 3 district 8314 non-null object 4 hours 7787 non-null object 5 lat 8314 non-null float64 6 lng 8314 non-null float64 7 rating 8314 non-null float64 8 price 3275 non-null object 9 avg_bill 3770 non-null object 10 middle_avg_bill 3109 non-null float64 11 middle_coffee_cup 529 non-null float64 12 chain 8314 non-null int64 13 seats 8314 non-null float64 14 street 8179 non-null object 15 is_24_7 8314 non-null bool dtypes: bool(1), float64(6), int64(1), object(8) memory usage: 1.0+ MB
Шаг 3. Исследовательский анализ данных¶
Анализ категорий заведений¶
Проанализируем виды категорий заведений, количество и долю заведений по категориям.
df_category = df.groupby('category')['name'].count().reset_index()
df_category.columns = ['category', 'count']
category_total = df_category['count'].sum()
df_category['share'] = round(
df_category['count'] / category_total * 100,
1
)
df_category.sort_values(by = 'count', ascending = False)
| category | count | share | |
|---|---|---|---|
| 3 | кафе | 2354 | 28.3 |
| 6 | ресторан | 2011 | 24.2 |
| 4 | кофейня | 1397 | 16.8 |
| 0 | бар,паб | 754 | 9.1 |
| 5 | пиццерия | 629 | 7.6 |
| 2 | быстрое питание | 601 | 7.2 |
| 7 | столовая | 313 | 3.8 |
| 1 | булочная | 255 | 3.1 |
#Зададим определенный цвет каждой категории для всего проекта
category_colors = {
"кафе": "#4682B4",
"ресторан": "#FF7F50",
"кофейня": "#228B22",
"бар,паб": "#9370DB",
"пиццерия": "#B22222",
"быстрое питание": "#8B4513",
"столовая": "#808080",
"булочная": "#EE82EE"
}
# Построим груговую диаграмму чтобы отразить доли категорий.
fig = go.Figure(px.pie(
df_category,
values='count',
names='category',
title="Доли категорий заведений Москвы",
color = 'category',
color_discrete_map = category_colors
))
fig.update_layout(width=700, height=450)
fig.show("png");
# Сформируем столбчатаю диаграмму чтобы оценить количественное
#распределение заведений по категориям
fig = go.Figure(px.bar(
df_category,
x = 'category',
y = 'count',
color = "category",
text = 'share',
title = 'Распределение заведений по категориям',
template = 'plotly_white',
hover_name = "category",
color_discrete_map = category_colors
))
fig.update_layout(
width=700,
height=400,
xaxis_title = 'Категории заведений',
yaxis_title = 'Количество заведений',
xaxis = {'categoryorder':'total descending'})
fig.show("png");
- Представлено восемь категорий заведений.
- Чаще всего встречаются
кафе(28.3%) ирестораны(24.3%), в сумме таких заведений более 50%. - На третьем месте по распространенности -
кофейни16.8%. - Реже встречаются
бары, пабы(9.1%),пиццерии(7.5%) ибыстрое питание(7.2%). - Среди самых редких категорий можно выделить
булочные(3%) истоловые(3.7%).
Вернуться в начало проекта
Анализ количества посадочных мест¶
Исследуем количество посадочных мест в местах по категориям: рестораны, кофейни, пиццерии, бары и так далее.
df.groupby('category')['seats'].describe()
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| category | ||||||||
| бар,паб | 754.0 | 66.168435 | 90.089388 | 0.0 | 0.0 | 40.0 | 94.0 | 480.0 |
| булочная | 255.0 | 49.427451 | 78.660499 | 0.0 | 0.0 | 8.0 | 70.0 | 478.0 |
| быстрое питание | 601.0 | 54.863561 | 83.942469 | 0.0 | 0.0 | 8.0 | 80.0 | 450.0 |
| кафе | 2354.0 | 43.903993 | 72.571346 | 0.0 | 0.0 | 0.0 | 60.0 | 481.0 |
| кофейня | 1397.0 | 51.702935 | 79.571190 | 0.0 | 0.0 | 5.0 | 80.0 | 480.0 |
| пиццерия | 629.0 | 59.120827 | 81.333853 | 0.0 | 0.0 | 30.0 | 80.0 | 455.0 |
| ресторан | 2011.0 | 68.055196 | 87.428239 | 0.0 | 0.0 | 40.0 | 100.0 | 481.0 |
| столовая | 313.0 | 46.434505 | 71.396036 | 0.0 | 0.0 | 4.0 | 76.0 | 428.0 |
После обработки аномальных значений, максимально количество посадочных мест в пределах от 428 ед. до 481 ед.
Медианное значение посадочных мест для заведений по категориям находится в пределах от 0 (кафе) до 40 (рестораны, бары/пабы).
Для лучшего понимания ситуации визуализируем данные и посмотрим на распределение количества посадочных мест.
sns.set_style('darkgrid')
plt.figure(figsize=(13, 6))
sns.stripplot(x = 'category', y = 'seats', data = df);
plt.title(
'Распределение посадочных мест в зависимостти от категории',
fontsize = 16
)
plt.xlabel('Категории заведений', fontsize = 14)
plt.ylabel('Количество посадочных мест', fontsize = 14)
plt.show();
Для заведений быстрого питания, булочных и столовых не характерна высокая посадка, и значения свыше 300 встречаются редко.
# check
df[['seats']].hist(bins=100, range=(0, 520), figsize=(18,3));
# подготовим данные для сортировки данных в порядке возрастания медианного значения
# Подготовим сводную таблицу по категориям и посадочным местам
seats_cat = df.pivot_table(index = 'name', columns='category', values='seats')
# Сохраним наименования категорий в порядке возрастания медианных значений посадки
# для сортировки
sort_index = seats_cat.median().sort_values().index
sort_index
Index(['кофейня', 'кафе', 'быстрое питание', 'булочная', 'столовая',
'пиццерия', 'бар,паб', 'ресторан'],
dtype='object', name='category')
# Посмотрим как распределяются посадочные места без аномалий на графике-скрипка
sns.set_style('darkgrid');
plt.figure(figsize=(13, 6));
custom_palette = [
"green",
"blue",
"brown",
"pink",
"gray",
"red",
"purple",
"orange",
]
sns.set_palette(custom_palette);
sns.violinplot(x = 'category', y = 'seats', data = df, cut=0, order = sort_index);
plt.title('Распределение посадочных мест в зависимости от категории', fontsize = 16)
plt.xlabel('Категории заведений', fontsize = 14)
plt.ylabel('Количество посадочных мест', fontsize = 14)
plt.show();
На графике можно увидеть, что:
Большая часть заведений по всем 8 категориям имеет посадку от 0 до 100 мест, чаще чем у других категорий встречаются большие значения посадочных мест у ресторанов, баров/пабов.
Имеют схожие распределения посадочных мест категории заведений столовая, булочная, быстрое питание и кофейня. Медианные значения колеблются между 4 и 8 местами, средние значения от 46 до 55 посадочных мест. Не большое количество посадочных мест характерно для заведений таких категорий.
Так же схожие распределения посадочных мест, с большим значением среднего и медианы у заведений категории бар/паб, ресторан и пиццерия. Медиана в пределах 30-40, среднее значение - от 59 до 68. Среди этих категорий чаще встречаются заведения с большим количеством посадочных мест, что и характерно для такого типа общепита.
Не характерные показатели у категории заведений - кафе. Для заведений категории кафе обычно характерно наличие посадочных мест, но по данным в таблице у большего количества заведений указано 0 посадочных мест, поэтому медианное значение - 0, при этом среднее значение 44.
Вернуться в начало проекта
Анализ сетевых заведений¶
Посмотрим на соотношение сетевых и несетевых заведений.
# заменим числовое обозначение сетевое/несетевое на более читаемое - словестное
df['chain_type'] = df['chain'].apply(lambda x: 'сетевое' if x == 1 else 'несетевое')
chain_type = df.groupby('chain_type', as_index = False)['name'].agg('count')
chain_type['share'] = round(chain_type['name'] / chain_type['name'].sum() *100)
chain_type
| chain_type | name | share | |
|---|---|---|---|
| 0 | несетевое | 5148 | 62.0 |
| 1 | сетевое | 3166 | 38.0 |
# Построим груговую диаграмму
fig = go.Figure(px.pie(
chain_type,
values='share',
names='chain_type',
title="Cоотношение сетевых и несетевых заведений питания Москвы",
#color_discrete_sequence=px.colors.sequential.Reds
))
fig.update_layout(width=700, height=450)
fig.show("png");
- 62% заведений относятся к несетевым;
- 38% заведений относятся к сетевым.
Посмотрим среди каких категорий чаще встречаются сетевые.
chain_category = df.pivot_table(
index = 'category',
values='name',
columns = 'chain',
aggfunc='count'
).reset_index()
chain_category['total'] = chain_category[0] + chain_category[1]
chain_category['share'] = round(
chain_category[1] / chain_category['total']*100,
1
)
chain_category = chain_category.sort_values(
by='share',
ascending=False
)
chain_category
| chain | category | 0 | 1 | total | share |
|---|---|---|---|---|---|
| 1 | булочная | 99 | 156 | 255 | 61.2 |
| 5 | пиццерия | 301 | 328 | 629 | 52.1 |
| 4 | кофейня | 686 | 711 | 1397 | 50.9 |
| 2 | быстрое питание | 370 | 231 | 601 | 38.4 |
| 6 | ресторан | 1295 | 716 | 2011 | 35.6 |
| 3 | кафе | 1585 | 769 | 2354 | 32.7 |
| 7 | столовая | 226 | 87 | 313 | 27.8 |
| 0 | бар,паб | 586 | 168 | 754 | 22.3 |
fig = go.Figure(px.bar(
chain_category,
x='category',
y='share',
text='share',
template='plotly_white',
color='category',
color_discrete_map = category_colors
))
# оформляем график
fig.update_layout(
title='% сетевых заведений от общего количества заведений Москвы по категориям',
width=1000,
height=400,
xaxis_title='Категория заведений',
yaxis_title='Доля сетевых заведений',
)
fig.show("png");
- Чаще всего встречаются несетевые заведения 62%.
- Среди кофейн, пиццерий и булочных больше сетевых заведений чем несетевых.
- В остальных категориях сетевых почти в два раза меньше, чем несетевых.
- Реже всего по отношению к общему числу сетевые заведения встречаются среди баров/пабов и столовых.
Вернуться в начало проекта
Анализ топ-15 сетевых заведений¶
Сгруппируем данные по названиям заведений и найдем топ-15 самых распространенных сетей в Москве.
#выделим сетевые заведения в отдельный датафрейм
df_chain = df.query('chain == 1')
# выведем на экран топ-15 сетевых заведений по количественному признаку
top_15_chain = df_chain.groupby('name').agg(
{'category' : pd.Series.mode, 'chain' : 'count'}
)
#переименуем столбец
top_15_chain = top_15_chain.rename(columns={'chain':'count'})
#отсортируем по убыванию и оставим только 15 наименований заведений
top_15_chain = top_15_chain.sort_values(
'count',
ascending = False
).reset_index().head(15)
top_15_chain
| name | category | count | |
|---|---|---|---|
| 0 | шоколадница | кофейня | 118 |
| 1 | доминос пицца | пиццерия | 76 |
| 2 | додо пицца | пиццерия | 74 |
| 3 | one price coffee | кофейня | 70 |
| 4 | яндекс лавка | ресторан | 68 |
| 5 | cofix | кофейня | 65 |
| 6 | prime | ресторан | 49 |
| 7 | хинкальная | кафе | 44 |
| 8 | кофепорт | кофейня | 42 |
| 9 | теремок | ресторан | 38 |
| 10 | кулинарная лавка братьев караваевых | кафе | 38 |
| 11 | чайхана | кафе | 36 |
| 12 | cofefest | кофейня | 32 |
| 13 | буханка | булочная | 32 |
| 14 | му-му | кафе | 27 |
#зададим стиль и размер графика
#sns.set_style('dark')
plt.figure(figsize = (15, 9))
#зададим график
sns.barplot(x = 'count', y = 'name', data = top_15_chain)
plt.title(
'Топ-15 заведений общественного питания Москвы по количественному признаку',
fontsize = 16)
plt.xlabel('Количество заведений', fontsize = 14)
plt.ylabel('Наименование заведений', fontsize = 14)
#plt.xticks(rotation = 80)
plt.grid()
plt.show();
В топ-15 по частоте заведений в Москве вошли такие заведения (в порядке убывания):
- шоколадница (кофейня) - 120 заведений;
- домино'с пицца (пиццерия) - 76 заведений;
- додо пицца (пиццерия) - 74 заведений;
- one price coffee (кофейня) - 71 заведений;
- яндекс лавка (ресторан) - 69 заведений;
- cofix (кофейня) - 65 заведений;
- prime (ресторан) - 50 заведений;
- хинкальная (кафе) - 44 заведений;
- кофепорт (кофейня) - 42 заведений;
- кулинарная лавка братьев караваевых (кафе) - 39 заведений;
- теремок (ресторан) - 38 заведений;
- чайхана (кафе)- 37 заведений;
- cofefest (кофейня) - 32 заведений;
- буханка (булочная) - 32 заведений;
- му-му (кафе) - 27 заведений.
На первом месте в рейтинге кофейня "Шоколадница", которая действительно встречается часто в Моске, эта сеть часто распологает свои кофейни в близи мест с большой проходимостью - возле метро и в торговых центрах, а так же возле бизнес центров. В топ-15 попали в оснвном заведения категорий кофейня и кафе по 4 в каждой категории, так же есть 3 ресторана, 2 пиццерии но очень популярные на 2 и 3 месте по распространенности по городу. Так же в топ-15 попала 1 булочная - "Буханка".
Эти сетевые заведения, обьединяет то что большинство из них часто встречаются в торговых центрах, в бизнес-центрах и в парках или возле них. То есть выбираются многолюдные места с большой проходимостью. Считаю что это важный момент при открытии заведения.
print('Общее количесто сетевых заведений:', df_chain['chain'].count())
Общее количесто сетевых заведений: 3166
# Выведем на график доли категорий заведений топ-15
total_top_15 = top_15_chain['count'].sum()
top_15_pivot = top_15_chain.pivot_table(
index = 'category',
values='count',
aggfunc='sum'
).reset_index()
top_15_pivot['share'] = round(top_15_pivot['count'] / total_top_15*100, 1)
top_15_pivot = top_15_pivot.sort_values(by='share', ascending=False)
top_15_pivot
#Отобразим общее количество сетевых заведений вошедшие в Топ-15 по категориям
fig = go.Figure(px.bar(
top_15_pivot,
x='category',
y='share',
template='plotly_white',
text='share',
color='category',
color_discrete_map = category_colors
))
# оформляем график
fig.update_layout(
title='Доля сетевых заведений Топ-15 по категориям',
width=700,
height=400,
xaxis_title='Категория заведений',
yaxis_title='Доля',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
Заведения попавшие в топ-15 можно объединить по категориям:
- 40.4% заведений попавших в топ-15 это кофейни, это логично, такой вид заведений не требует больших пллощадей, большой кухни, большого ассортимента и большого колличества персонала что упрощает работу и возможность распространения по городу.
- 19.2% заведений составляют рестораны;
- чуть меньше 18.5% это пиццерии;
- 17.9% в топ-15 попали такие заведения как кафе;
- меньше всего среди заведений топ-15 это булочные - 4%, хотя среди булочных чаще всего встречаются сетевые заведения.
#сгруппируем данные сетевых заведений Топ-15 по районам Москвы
district_chain = df_chain.groupby(
['district', 'category', 'name']
).agg({'chain' : 'count'})
district_chain = district_chain.sort_values(
'chain',
ascending = False
).reset_index()
district_chain = district_chain.rename(columns={'chain':'count'})
district_chain = district_chain[district_chain['name'].isin(
top_15_chain['name']
)]
#зададим столбчатую диаграмму
fig = go.Figure(px.bar(
district_chain,
x='count',
y='district',
color='category',
color_discrete_map = category_colors
))
# оформляем график
fig.update_layout(
title='Распределение категории сетевых заведений Топ-15 по районам Москвы',
width=900,
height=400,
xaxis_title='Количество заведений',
yaxis_title='Название района',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
На Центральный административный округ приходится большая часть сетевых заведений из рейтинка топ-15, больше всего кофейн, ресторанов и кафе. В остальных районах количество заведений распределяется примерно равномерно, но среди категорий пиццерии встречаются чаще чем кафе. Вероятно что на это влияет большое количество спальных районов, в отличии от Центрального округа, где больше прогулочных и тусовочных мест.
В Северо-Западном административном округе меньше популярных сетевых заведений чем в остальных округах.
Мы посмотрели на данные в разрезе топ-15 самых популярных сетевых заведений Москвы, теперь посмотрим в целом по всем заведениям.
Вернуться в начало проекта
Анализ по административным округам¶
Изучим какие административные районы Москвы присутствуют в датасете. Отобразим общее количество заведений и количество заведений каждой категории по районам.
print('В датасете присутствуют следующие административные районы Москвы:')
print(' ')
print(df['district'].value_counts())
print('_'*50)
print('Всего представлено районов Москвы:', df['district'].nunique())
В датасете присутствуют следующие административные районы Москвы: Центральный административный округ 2225 Южный административный округ 890 Северо-Восточный административный округ 888 Северный административный округ 874 Западный административный округ 825 Восточный административный округ 786 Юго-Восточный административный округ 713 Юго-Западный административный округ 704 Северо-Западный административный округ 409 Name: district, dtype: int64 __________________________________________________ Всего представлено районов Москвы: 9
# сгруппируем данные заведений по категориям по районам Москвы
district_cat = df.groupby(['district', 'category']).agg({'name' : 'count'})
district_cat = district_cat.sort_values(
'name',
ascending = False
).reset_index()
district_cat = district_cat.rename(columns={'name':'count'})
# вычислим общее количество заведений по району и посчитаем долю
district_cat['total_district'] = district_cat.groupby(
'district'
)['count'].transform(sum)
district_cat = district_cat.sort_values(
['total_district', 'count'],
ascending = False
)
district_cat['share'] = round(
district_cat['count']/district_cat['total_district']*100,
1
)
district_cat
| district | category | count | total_district | share | |
|---|---|---|---|---|---|
| 0 | Центральный административный округ | ресторан | 662 | 2225 | 29.8 |
| 1 | Центральный административный округ | кафе | 459 | 2225 | 20.6 |
| 2 | Центральный административный округ | кофейня | 425 | 2225 | 19.1 |
| 3 | Центральный административный округ | бар,паб | 364 | 2225 | 16.4 |
| 23 | Центральный административный округ | пиццерия | 113 | 2225 | 5.1 |
| ... | ... | ... | ... | ... | ... |
| 55 | Северо-Западный административный округ | пиццерия | 40 | 409 | 9.8 |
| 60 | Северо-Западный административный округ | быстрое питание | 30 | 409 | 7.3 |
| 66 | Северо-Западный административный округ | бар,паб | 23 | 409 | 5.6 |
| 68 | Северо-Западный административный округ | столовая | 18 | 409 | 4.4 |
| 71 | Северо-Западный административный округ | булочная | 12 | 409 | 2.9 |
72 rows × 5 columns
# Построим график распределения категорий заведений по районам Москвы
fig = go.Figure(px.bar(
district_cat,
x='share',
y='district',
text='share',
color='category',
color_discrete_map = category_colors
))
# оформляем график
fig.update_layout(
title='Доли категории заведений по районам Москвы',
width=900,
height=400,
xaxis_title='Доля заведений по категориям',
yaxis_title='Название района',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
Больше всего заведений в Центральном районе Москвы, самая популярная категория это рестораны, второе место разделяют кафе и кафейни, далее бары/пабы. Существенно реже встречаются булочные, столовые, быстрое питание и пиццерии.
В остальных административных округах Москвы (за исключением Северо-Западного) количество заведений распределяется почти равномерно, и большей популярностью в этих округах пользуются кафе, второе место занимают рестораны, далее кофейни, остальных категорий представлено значительно меньше и они составляют малую долю.
Меньше всего заведений приходится на долю Северо-Западного района, почти в 5,5 раз меньше чем в Центральном.
Вернуться в начало проекта
Анализ рейтинга заведений¶
Визуализируем распределение средних рейтингов по категориям заведений.
rating_cat = df.groupby(
'category',
as_index=False
)['rating'].agg('mean').round(2)
rating_cat.sort_values(by = 'rating', ascending = False)
rating_cat = rating_cat.sort_values(by = 'rating', ascending = False)
fig = go.Figure(px.bar(
rating_cat,
x='rating',
y='category',
text='rating',
template='plotly_white',
color='category',
color_discrete_map = category_colors
))
# оформляем график
fig.update_layout(
title='Распределение средних рейтингов по категориям заведений',
width=700,
height=400,
xaxis_title='Средний рейтинг',
yaxis_title='Название категорий',
)
fig.update_xaxes(range=[4, 4.4])
fig.show("png");
В целом, различия между рейтингами разных типов заведений не существенные:
- Между категориями средний рейтинг заведений распределяется между 4.0 и 4.4;
- самый высокий средний рейтинг у категории бары/пабы 4.39 пунктов;
- на втором месте категория пиццерия 4.3 пункта, далее ресторан - 4.29 пунктов и кофейня 4.28 пунктов;
- самый низкий рейтинг у категории быстрое питание - 4.05, немного выше у кафе - 4.12 и столовой 4.21.
Вернуться в начало проекта
Карта заведений¶
Построим фоновую картограмму (хороплет) со средним рейтингом заведений каждого района.
district_rating = df.groupby(
'district', as_index=False
)['rating'].agg('mean').round(2).sort_values(
by = 'rating',
ascending = False
)
district_rating
| district | rating | |
|---|---|---|
| 5 | Центральный административный округ | 4.38 |
| 2 | Северный административный округ | 4.24 |
| 4 | Северо-Западный административный округ | 4.21 |
| 1 | Западный административный округ | 4.18 |
| 8 | Южный административный округ | 4.18 |
| 0 | Восточный административный округ | 4.17 |
| 7 | Юго-Западный административный округ | 4.17 |
| 3 | Северо-Восточный административный округ | 4.15 |
| 6 | Юго-Восточный административный округ | 4.10 |
# читаем файл и сохраняем в переменной
with open('/Users/mariapolivanova/Downloads/admin_level_geomap.geojson', 'r') as f:
geo_json = json.load(f)
# загружаем JSON-файл с границами округов Москвы
state_geo = '/Users/mariapolivanova/Downloads/admin_level_geomap.geojson'
# moscow_lat - широта центра Москвы, moscow_lng - долгота центра Москвы
moscow_lat, moscow_lng = 55.751244, 37.618423
# создаём карту Москвы
m = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём хороплет с помощью конструктора Choropleth и добавляем его на карту
rating_map = folium.Choropleth(
geo_data=state_geo,
data=district_rating,
columns=['district', 'rating'],
key_on='feature.name',
fill_color='YlOrBr',
fill_opacity=0.8,
legend_name='Средний рейтинг заведений по районам Москвы',
).add_to(m)
#добавим подписи административным округам при наведении курсора на них
rating_map.geojson.add_child(
folium.features.GeoJsonTooltip(['name',], labels=False)
)
# выводим карту
m
- Самый высокий средний рейтинг у заведений Центрального округа Москвы - 4.38. Вероятно из-за большой конкуренции заведения стараются держать планку.
- Самый низкий рейтинг среди заведений Юго-Восточного округа Москвы. Данный район известен крупными рынками, производственным сектором, и более бюджетными ценами на жильё, что может говорить о том что уровень жизни среди населения в этом районе ниже и возможно заведения в этих районах более бюджетные, что может влиять на качество обслуживания, а следовательно и на рейтинги заведений.
Отобразим все заведения датасета на карте с помощью кластеров средствами библиотеки folium
# создаём карту Москвы
m_0 = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём пустой кластер, добавляем его на карту
marker_cluster = MarkerCluster().add_to(m_0)
# пишем функцию, которая принимает строку датафрейма,
# создаёт маркер в текущей точке и добавляет его в кластер marker_cluster
def create_clusters(row):
Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} {row['rating']}",
).add_to(marker_cluster)
# применяем функцию create_clusters() к каждой строке датафрейма
df.apply(create_clusters, axis=1)
# выводим карту
m_0
По карте можно наблюдать распределение заведений по территории Москвы, больше всего сконцентрировано в Центральном районе.
Далее изучим на каких улицах сконцентрировано большее количество заведений.
Вернуться в начало проекта
Топ-15 улиц по количеству заведений¶
Составим список в которые войдут 15 улиц Москвы с самым большим количеством заведений общественного питания.
# в сводной таблице посчитаем количество заведений по каждой улице
street_df = df.pivot_table(
index='street',
values='name',
aggfunc='count'
).sort_values(by='name', ascending=False).head(15)
# сформируем список с наименованием улиц
top_15_street = street_df.index
street_df = street_df.reset_index()
street_df = street_df.rename(columns={'name':'count'})
print('Топ-15 улиц по количеству заведений:')
display(street_df)
Топ-15 улиц по количеству заведений:
| street | count | |
|---|---|---|
| 0 | проспект мира | 184 |
| 1 | профсоюзная улица | 122 |
| 2 | ленинский проспект | 101 |
| 3 | проспект вернадского | 97 |
| 4 | дмитровское шоссе | 87 |
| 5 | каширское шоссе | 76 |
| 6 | варшавское шоссе | 75 |
| 7 | ленинградский проспект | 72 |
| 8 | ленинградское шоссе | 69 |
| 9 | мкад | 65 |
| 10 | люблинская улица | 60 |
| 11 | улица вавилова | 53 |
| 12 | кутузовский проспект | 53 |
| 13 | пятницкая улица | 48 |
| 14 | улица миклухо-маклая | 47 |
#сгруппируем данные по улицам и категориям,
#оставим только улицы из списка топ-15
street_cat = df.groupby(['street', 'category']).agg({'name' : 'count'})
street_cat = street_cat.sort_values('name', ascending = False).reset_index()
street_cat = street_cat.rename(columns={'name':'count'})
street_cat = street_cat[street_cat['street'].isin(top_15_street)]
# Построим график распределения категорий заведений по топ-15 улицам Москвы
fig = px.bar(
street_cat,
x='count',
y='street',
text='count',
color='category',
color_discrete_map = category_colors
)
# оформляем график
fig.update_layout(
title='Распределение категории заведений по самым популярным улицам Москвы',
width=950,
height=450,
xaxis_title='Количество заведений',
yaxis_title='Название улицы',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
В топ-15 популярных по количеству заведений улиц вошли в порядке убывания: проспект Мира; Профсоюзная улица; проспект Вернадского; Ленинский проспект; Ленинградский проспект; Дмитровское шоссе; Каширское шоссе; Варшавское шоссе; Ленинградское шоссе; МКАД; Люблинская улица; улица Вавилова; Кутузовский проспект; улица Миклухо-Маклая; Пятницкая улица.
Больше всего заведений общественного питания на проспекте Мира - 184, из которых самая популярная категория - кафе, чуть менее популярны рестораны, кофейни. Меньше всего представлено столовых и булочных.
На остальных улицах из топ-15 в основном схожая ситуация - в тройку самых популярных типов заведений входят кафе, рестораны и кофейни.
Достаточно часто (более 9 заведений на 1 улицу) можно встретить бары/пабы на улицах: проспект Мира; Ленинский проспект; Ленинградский проспект; Пятницкая улица. Хотя это проспекты (за исключением Пятницкой улицы) и имеют достаточно большую протяженность, поэтому, вероятно они достаточно рассредоточены на карте. А вот Пятницкая улица не большая по протяженности и находится в Центральном районе.
Стоит отметить, что в топ-15 улиц попала МКАД - Московская Кольцевая Автомобильная Дорога – это крупнейшая автомобильная развязка в Москве, которая представляет собой кольцо длиной около 109 километров, что превышает протяженность самой длинной улицы Москвы - Варшавское шоссе (длина которого 22,5 км.) почти в 5 раз. При этом МКАД на 10 месте по количеству заведений общественного питания.
Вернуться в начало проекта
Улицы с 1 заведением¶
Проанализируем улицы с 1 заведением.
street_one_object = df.pivot_table(
index='street',
values='name',
aggfunc='count'
).sort_values(by='name')
street_one_object = street_one_object[street_one_object['name'] == 1]
street_one_object = street_one_object.index
print('Улиц с одним заведением в Москве:', len(street_one_object))
Улиц с одним заведением в Москве: 426
# создадим сводную таблицу с улицами на которых по 1 заведению для вывода на карту Москвы
one_obj_street = df[df['street'].isin(street_one_object)]
one_obj_street = one_obj_street.groupby(
['street', 'name', 'category', 'lat', 'lng']
).agg({'chain' : 'count'})
one_obj_street = one_obj_street.reset_index()
one_obj_street = one_obj_street.rename(columns={'chain':'count'})
# создаём карту Москвы
m_1 = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём пустой кластер, добавляем его на карту
marker_cluster = MarkerCluster().add_to(m_1)
def create_clusters(row):
# сохраняем URL-адрес изображения со значком с icons8,
# это путь к файлу на сервере icons8
icon_url = 'https://img.icons8.com/?size=100&id=MU6RngCQ3iWG&format=png'
# создаём объект с собственной иконкой размером 30x30
icon = CustomIcon(icon_url, icon_size=(30, 30))
# создаём маркер с иконкой icon и добавляем его в кластер
Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} {row['category']}",
icon=icon,
).add_to(marker_cluster)
# применяем функцию для создания кластеров к каждой строке датафрейма
one_obj_street.apply(create_clusters, axis=1)
# выводим карту
m_1
one_obj_pivot = one_obj_street.groupby(
'category'
).agg({'name' : 'count'}).sort_values('name', ascending = False).reset_index()
one_obj_pivot = one_obj_pivot.rename(columns={'name':'count'})
one_obj_total = one_obj_pivot['count'].sum()
one_obj_pivot['share'] = round(one_obj_pivot['count'] / one_obj_total * 100, 1)
one_obj_pivot.sort_values(by = 'count', ascending = False)
# Построим график распределения заведений по категориям среди улиц с 1 заведением
fig = px.bar(
one_obj_pivot,
x='category',
y='share',
text='share',
color = 'category',
color_discrete_map = category_colors
)
# оформляем график
fig.update_layout(
title='Доля заведений по категориям среди улиц с 1 заведением',
width=700,
height=400,
xaxis_title='Категория заведений',
yaxis_title='Доля заведений',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
- По всей Москве встречаются улицы с одним заведением, то есть такое явление нормально.
- Чаще всего среди одиночных заведений встречаются кафе, рестораны и кофейни.
- Реже всех встречаются заведения категории булочная.
- Вероятно что улицы не длинные и находятся в спальных районах.
Вернуться в начало проекта
Анализ ценового диапазона¶
Значения средних чеков заведений хранятся в столбце middle_avg_bill. Эти числа показывают примерную стоимость заказа в рублях, которая чаще всего выражена диапазоном.
Посчитаем медиану этого столбца для каждого района. Используем это значение в качестве ценового индикатора района.
Построим фоновую картограмму (хороплет) с полученными значениями для каждого района.
distr_avg_bill = df.query(
'middle_avg_bill != "NaN"'
).groupby('district')['middle_avg_bill'].median()
distr_avg_bill = distr_avg_bill.reset_index().sort_values(
by = 'middle_avg_bill',
ascending = False
)
distr_avg_bill
| district | middle_avg_bill | |
|---|---|---|
| 1 | Западный административный округ | 1000.0 |
| 5 | Центральный административный округ | 1000.0 |
| 4 | Северо-Западный административный округ | 700.0 |
| 2 | Северный административный округ | 650.0 |
| 7 | Юго-Западный административный округ | 600.0 |
| 0 | Восточный административный округ | 550.0 |
| 3 | Северо-Восточный административный округ | 500.0 |
| 8 | Южный административный округ | 500.0 |
| 6 | Юго-Восточный административный округ | 450.0 |
# создаём карту Москвы
m_2 = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём хороплет с помощью конструктора Choropleth и добавляем его на карту
avg_bill_map = Choropleth(
geo_data=state_geo,
data=distr_avg_bill,
columns=['district', 'middle_avg_bill'],
key_on='feature.name',
fill_color = 'YlOrBr',
legend_name='Средний чек заведений по районам',
text='middle_avg_bill'
).add_to(m_2)
# добавим подписи административным округам
# отображающиеся при наведении курсора на них
avg_bill_map.geojson.add_child(
folium.features.GeoJsonTooltip(['name',], labels=False)
)
# выводим карту
m_2
- Самый высокий показатель среднего чека в 1 000 руб. по районам Москвы у Центрального административного округа и Западного административного округа. Эта сумма в два раза больше чем у районов с наименьшим показателем среднего чека.
- Самые низкие средние чеки в Северо-Восточномй административном округе (500.0 руб.); Южном административном округе (500.0 руб.) и Юго-Восточном административном округе.
- В остальных районах медианный показатель среднего чека в диапазоне 550 - 700 руб., что на 30-42.5% меньше чем Центральном и Западном районах.
Стоит иметь ввиду, что существенная разность в соотношении заведений по округам Москвы, может оказывать влияние на величину среднего чека, так преобладающая доля ресторанов и пабов в ЦАО с высокими чеками повышает медианное значение, по сравнению, например, с не большим количеством заведений в ЮАО.
Так же на цены в заведениях сильно влияет стоимость аренды помещений, ведь в Центральном и Западном районах Москвы стоимость аренды помещений может встречаться значительно выше чем в более отдаленных районах. В Западном районе Москвы больше элитной недвижимости и бизнес-центров, что делает этот район более престижным, и цены на аренду помещений выше чем в менее пристижных районах.
Вернуться в начало проекта
Анализ круглосуточных заведений¶
Исследуем круглосуточные и не круглосуточные заведения.
df_24_7 = df.query('is_24_7 == True')
print('Всего круглосуточных заведений в датафрейме:', df_24_7['name'].count())
print(f'Доля круглосуточных заведений: {df_24_7.name.count()/df.name.count():.1%}')
Всего круглосуточных заведений в датафрейме: 726 Доля круглосуточных заведений: 8.7%
pivot_24_7 = df_24_7.groupby(['category']).agg({
'chain' : 'count',
'rating' : 'median',
'seats' : 'mean',
'middle_avg_bill' : 'mean'
})
pivot_24_7 = pivot_24_7.reset_index()
pivot_24_7 = pivot_24_7.rename(columns={'chain':'count'})
pivot_24_7 = pivot_24_7.sort_values(by = 'count', ascending = False)
pivot_24_7.style.format({
'middle_avg_bill' : '{:.0f}',
'seats' : '{:.0f}',
'rating' : '{:.1f}'
})
| category | count | rating | seats | middle_avg_bill | |
|---|---|---|---|---|---|
| 3 | кафе | 266 | 4.1 | 36 | 562 |
| 2 | быстрое питание | 150 | 4.1 | 42 | 280 |
| 6 | ресторан | 132 | 4.3 | 59 | 1014 |
| 4 | кофейня | 59 | 4.2 | 57 | 1423 |
| 0 | бар,паб | 52 | 4.4 | 64 | 1184 |
| 5 | пиццерия | 31 | 4.2 | 49 | 475 |
| 1 | булочная | 24 | 4.2 | 82 | 360 |
| 7 | столовая | 12 | 4.2 | 36 | 312 |
plt.figure(figsize=(10, 5))
custom_palette = [
"blue",
"brown",
"orange",
"green",
"purple",
"red",
"pink",
"gray"
]
sns.set_palette(custom_palette)
sns.barplot(
x='category',
y='count',
data=pivot_24_7
)
plt.title('Распределение круглосуточных заведений Москвы по категориям')
plt.xlabel('Категории заведений')
plt.ylabel('Количество заведений')
plt.show();
district_24_7 = df_24_7.groupby(['district', 'category']).agg({'chain' : 'count'})
district_24_7 = district_24_7.reset_index()
district_24_7 = district_24_7.rename(columns={'chain':'count'})
district_24_7 = district_24_7.sort_values(by = 'count', ascending = False)
fig = px.bar(
district_24_7,
x='count',
y='district',
color='category',
text='count',
color_discrete_map = category_colors
)
# оформляем график
fig.update_layout(
title='Распределение категории круглосуточных заведений по районам Москвы',
width=950,
height=400,
xaxis_title='Количество круглосуточных заведений',
yaxis_title='Название района',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
- Круглосуточные заведения составляют 8.7% от всех заведений Москвы из датафрейма.
- Чаще всего среди круглосуточных заведений можно встретить кафе, быстрое питание и рестораны.
- Реже всего встречаются круглосуточные столовые.
- Средний рейтинг между категориями круглосуточных заведений варьируется в пределах 4.1 и 4.4 (самый высокий у категории бар,паб).
- Самая высокий средний показатель посадки среди категорий круглосуточных заведений у булочных (86 мест).
- Самый высокий седний чек среди круглосуточных заведений Москвы у ресторанов, кофейн и баров,пабов.
- Больше всего круглосуточных заведений в Центральном округе Москвы, а меньше всего - в Северо-Западном.
Вернуться в начало проекта
Анализ заведений с низкими рейтингами¶
Построим графики бокс плот - отражающие статистические величины, для определения категории низких рейтингов.
# Подготовим сводную таблицу по категориям и рейтингам
rating_cat = df.pivot_table(index = 'name', columns='category', values='rating')
# Сохраним наименования категорий в порядке возрастания медианных рейтингов для сортировки
index_sort = rating_cat.mean().sort_values().index
index_sort
Index(['быстрое питание', 'кафе', 'столовая', 'булочная', 'ресторан',
'пиццерия', 'кофейня', 'бар,паб'],
dtype='object', name='category')
# построим ящик с усами по рейтингам заведений с разбивкой по категориям
plt.figure(figsize = (15, 7))
custom_palette = [
"brown",
"blue",
"gray",
"pink",
"orange",
"red",
"green",
"purple",
]
sns.set_palette(custom_palette)
ax = sns.boxplot(x='category', y='rating', data=df, order=index_sort)
plt.title('Распределение рейтинговых оценок по категориям заведений Москвы', fontsize = 17)
plt.xlabel('Категории заведений')
plt.ylabel('Рейтинг заведений')
plt.show();
- У всех заведений в датафрейме выставлены рейтинги
- Максимальное значение 5, минимальное 1.
- Для большинства категорий выбросами являются рейтинги меньше 3.5, для всех категорий ниже 3 баллов.
Рассмотрим заведения с балом меньше трех единиц.
low_rating = df.query(
'rating <= 3.0'
).groupby(['category']).agg({'name' : 'count', 'middle_avg_bill' : 'median'})
low_rating = low_rating.reset_index()
low_rating = low_rating.sort_values(by = 'name', ascending = False)
low_rating
| category | name | middle_avg_bill | |
|---|---|---|---|
| 3 | кафе | 118 | 750.0 |
| 6 | ресторан | 37 | NaN |
| 2 | быстрое питание | 35 | 325.0 |
| 4 | кофейня | 18 | NaN |
| 5 | пиццерия | 9 | 900.0 |
| 0 | бар,паб | 8 | NaN |
| 7 | столовая | 7 | 237.5 |
| 1 | булочная | 2 | 325.0 |
- Чаще всего среди заведений с низким рейтингом встречаются кафе.
- Реже всего среди заведений низкий рейтинг бывает у булочных.
- У заведений с низким рейтингом ниже и средний чек, что логично.
- Среди заведений с низким рейтингом смый высокий чек у заведений категории пиццерия.
Вернуться в начало проекта
Вывод:¶
По изученным данным заведений Москвы можно выделить:
Всего представлено восемь категорий заведений: чаще всего встречаются кафе (28.3%) и рестораны (24.3%), на третьем месте по распространенности кофейни 16.8%. Среди редких категорий можно выделить булочные (3%) и столовые(3.7%).
Большая часть заведений по всем 8 категориям имеет посадку от 0 до 100 мест, чаще чем у других категорий встречаются большие значения посадочных мест у ресторанов, баров/пабов. У заведений категорий столовая, булочная, быстрое питание и кофейня, медианные значения колеблются между 4 и 8 местами, средние значения от 46 до 55 посадочных мест. Не большое количество посадочных мест характерно для заведений таких категорий.
Не характерные показатели у категории заведений - кафе. Для заведений категории кафе обычно характерно наличие посадочных мест, но по данным в таблице у большего количества заведений указано 0 посадочных мест, поэтому медианное значение - 0, при этом среднее значение 44.
Чаще всего встречаются несетевые заведения их 62% в датафрейме. Среди кофейн, пиццерий и булочных больше сетевых заведений чем несетевых. В остальных категориях сетевых почти в два раза меньше, чем несетевых. Реже всего по отношению к общему числу сетевые заведения встречаются среди баров/пабов и столовых.
В топ-15 по частоте заведений в Москве На первом месте в рейтинге кофейня "Шоколадница", которая действительно встречается часто в Моске, эта сеть часто распологает свои кофейни в близи мест с большой проходимостью - возле метро и в торговых центрах, а так же возле бизнес центров и вокзалов. В топ-15 попали в оснвном заведения категорий кофейня и кафе по 4 в каждой категории, так же есть 3 ресторана, 2 пиццерии но очень популярные на 2 и 3 месте по распространенности по городу. Так же в топ-15 попала 1 булочная - "Буханка".
Эти сетевые заведения, обьединяет то что большинство из них часто встречаются в торговых центрах, в бизнес-центрах и в парках или возле них. То есть выбираются многолюдные места с большой проходимостью. Считаю что это важный момент при открытии заведения.
Большая часть сетевых заведений из рейтинка топ-15 приходится на Центральный административный округ, где представлены в оснавном кофейни, рестораны и кафе. В остальных районах количество заведений распределяется примерно равномерно, но среди категорий пиццерии встречаются чаще чем кафе. Вероятно что на это влияет большое количество спальных районов, в отличии от Центрального округа, где больше прогулочных и тусовочных мест.
- Всего в датасете представлено 9 административных округов Москвы. Больше всего заведений в Центральном районе Москвы, самая популярная категория это рестораны, второе место разделяют кафе и кофейни, далее бары/пабы. Существенно реже встречаются булочные, столовые, быстрое питание и пиццерии. Меньше всего заведений приходится на долю Северо-Западного района, почти в 5,5 раз меньше чем в Центральном.
В остальных административных округах Москвы (за исключением Северо-Западного) количество заведений распределяется почти равномерно, и большей популярностью в этих округах пользуются кафе, второе место занимают рестораны, далее кофейни, остальных категорий представлено значительно меньше и они составляют малую долю.
В целом, различие между средними рейтингами разных категорий заведений не существенное, распределяется между 4.0 и 4.4. Самый высокий средний рейтинг у категории бары/пабы 4.39 пунктов, на втором месте категория пиццерия 4.3 пункта, далее ресторан - 4.29 пунктов и кофейня 4.28 пунктов. Самый низкий рейтинг у категории быстрое питание - 4.05, немного выше у кафе - 4.12 и столовой 4.21.
Если рассматривать средний рейтинг среди районов Москвы, то самый высокий средний рейтинг у заведений Центрального округа Москвы - 4.38. Вероятно из-за большой конкуренции заведения стараются держать планку. Самый низкий рейтинг среди заведений Юго-Восточного округа Москвы. Данный район известен крупными рынками, производственным сектором, и более бюджетными ценами на жильё, что может говорить о том что уровень жизни среди населения в этом районе ниже и возможно заведения в этих районах более бюджетные, что может влиять на качество обслуживания, а следовательно и на рейтинги заведений.
Среди самых популярных по количеству заведений общественного питания первое место занимает проспект Мира - 184 заведения, из которых самая популярная категория - кафе, чуть менее популярны рестораны, кофейни. Меньше всего представлено столовых и булочных. На остальных улицах из топ-15 в основном схожая ситуация - в тройку самых популярных типов заведений входят кафе, рестораны и кофейни.
Достаточно часто (более 9 заведений на 1 улицу) можно встретить бары/пабы на улицах: проспект Мира; Ленинский проспект; Ленинградский проспект; Пятницкая улица. Хотя это проспекты (за исключением Пятницкой улицы) и имеют достаточно большую протяженность, поэтому, вероятно они достаточно рассредоточены на карте. А вот Пятницкая улица не большая по протяженности и находится в Центральном районе.
- Самый высокий показатель среднего чека в 1 000 руб. по районам Москвы у Центрального административного округа и Западного административного округа. Эта сумма в два раза больше чем у районов с наименьшим показателем среднего чека. Самые низкие средние чеки в Северо-Восточномй административном округе (500.0 руб.); Южном административном округе (500.0 руб.) и Юго-Восточном административном округе. В остальных районах медианный показатель среднего чека в диапазоне 575 - 700 руб., что на 30-42.5% меньше чем Центральном и Западном районах.
На цены в заведениях сильно влияет стоимость аренды помещений, ведь в Центральном и Западном районах Москвы стоимость аренды помещений очень высока. В Западном районе Москвы больше элитной недвижимости и бизнес-центров, что делает этот район более престижным, вот и цены на аренду помещений выше чем в менее пристижных районах.
Круглосуточные заведения составляют 8.7% от всех заведений Москвы из датафрейма. Чаще всего среди круглосуточных заведений можно встретить кафе, быстрое питание и рестораны. Реже всего встречаются круглосуточные столовые. Средний рейтинг между категориями круглосуточных заведений варьируется в пределах 4.1 и 4.4 (самый высокий у категории бар,паб). Самая высокий средний показатель посадки среди категорий круглосуточных заведений у булочных (86 мест). Самый высокий средний чек среди круглосуточных заведений Москвы у ресторанов, кофейн и баров,пабов. Больше всего круглосуточных заведений в Центральном округе Москвы, а меньше всего - в Северо-Западном как и в целом по всем заведениям.
Чаще всего среди заведений с низким рейтингом встречаются кафе. Реже всего среди заведений низкий рейтинг бывает у булочных. У заведений с низким рейтингом ниже и средний чек, что логично. Среди заведений с низким рейтингом смый высокий чек у заведений категории пиццерия.
Вернуться в начало проекта
Шаг 4. Детализированное исследование: открытие кофейни¶
Основателям фонда «Shut Up and Take My Money» не даёт покоя успех сериала «Друзья». Их мечта — открыть такую же крутую и доступную, как «Central Perk», кофейню в Москве.
Будем считать, что заказчики не боятся конкуренции в этой сфере, ведь кофеен в больших городах уже достаточно.
Попробуем определить, осуществима ли мечта клиентов.
Анализ количества и расположения кофейн¶
Посмотрим сколько всего кофейн Москвы представлено в полученном для исследования датафрейме и как они распределены по районам Москвы.
# выделим кофейни в отдельный датафрейм
df_coff = df.query('category == "кофейня"')
print('Всего количество кофейн:', df_coff.shape[0])
# В сводной таблице сгруппируем кофейни по районам и посчитаем их количество
coff_pivot = df_coff.groupby(['district']).agg({'name' : 'count'})
coff_pivot = coff_pivot.reset_index()
coff_pivot = coff_pivot.rename(columns={'name':'count'})
coff_pivot = coff_pivot.sort_values(by = 'count', ascending = False)
# Построим столбчатый график распределения кофейн по районам
fig = px.bar(
coff_pivot,
x='count',
y='district',
text='count',
color = 'district'
)
# оформляем график
fig.update_layout(
title='Распределение кофейн по районам Москвы',
width=950,
height=400,
xaxis_title='Количество кофейн',
yaxis_title='Название района',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
Всего количество кофейн: 1397
# создаём карту Москвы
m_3 = Map(location=[moscow_lat, moscow_lng], zoom_start=10, tiles='Cartodb Positron')
# создаём хороплет с помощью конструктора Choropleth и добавляем его на карту
count_map = folium.Choropleth(
geo_data=state_geo,
data=coff_pivot,
columns=['district', 'count'],
key_on='feature.name',
fill_color='YlOrBr',
fill_opacity=0.8,
legend_name='Количество кофейн по районам Москвы',
).add_to(m_3)
#добавим подписи административным округам при наведении курсора на них
count_map.geojson.add_child(folium.features.GeoJsonTooltip(['name',], labels=False))
# создаём пустой кластер, добавляем его на карту
marker_cluster_2 = MarkerCluster().add_to(m_3)
# пишем функцию, которая принимает строку датафрейма,
# создаёт маркер в текущей точке и добавляет его в кластер marker_cluster
def create_clusters(row):
Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} {row['rating']}",
).add_to(marker_cluster_2)
# применяем функцию create_clusters() к каждой строке датафрейма
df_coff.apply(create_clusters, axis=1)
# выводим карту
m_3
- Всего 1413 кофейн.
- Больше всего кофейн в Центральном районе Москвы, их количество превышает более чем в два раза над остальными района - 428.
- В остальных административных округах кофейн менее 200 заведений на район, лидеры среди них - Северный, Северо-Восточный и Западный административные округа..
- Меньше всего кофейн (62) в Северо-Западном административном округе.
- По карте сложно определить особенности расположения кофейн, но в целом, они встречаются в первых этажах многоквартирных домов, в торговых центрах, в бизнес центрах, возле парковых зон и метро.
Вернуться в начало проекта
Исследование часов работы кофейн¶
Посмотрим как часто встречаются круглосуточные кофейни.
# заменим булевое обозначение в столбце is_24_7 - True/False на более читаемое - словестное
df_coff['work_hours_type'] = df_coff['is_24_7'].apply(
lambda x: 'не круглосуточно' if x == False else 'круглосуточно'
)
hours_type = df_coff.groupby('work_hours_type', as_index = False)['name'].agg('count')
hours_type['share'] = round(hours_type['name'] / hours_type['name'].sum() *100, 1)
hours_type
| work_hours_type | name | share | |
|---|---|---|---|
| 0 | круглосуточно | 59 | 4.2 |
| 1 | не круглосуточно | 1338 | 95.8 |
# Построим груговую диаграмму
fig = go.Figure(
data=[go.Pie(labels=hours_type['work_hours_type'], values=hours_type['share'])]
)
fig.update_layout(
title='Cоотношение круглосуточных и не круглосуточных кофейн Москвы',
width=700,
height=400,
annotations=[dict(
x=1.15,
y=1.05,
text='Время работы:',
showarrow=False
)]
)
fig.show("png");
# сгруппируем данные по районам, только для круглосуточных кофейн
coff_type = df_coff.query(
'is_24_7 == True'
).groupby(['district'], as_index=False).agg({
'name' : 'count',
'rating' : 'mean'
}).sort_values(by='name', ascending = False).reset_index()
coff_type = coff_type.rename(columns={'name':'count'})
#зададим столбчатую диаграмму
fig = px.bar(coff_type,
x='count',
y='district',
text='count',
color='rating'
)
# оформляем график
fig.update_layout(
title='Распределение круглосуточных кофейн по районам Москвы',
width=700,
height=400,
xaxis_title='Количество заведений',
yaxis_title='Название района',
yaxis={'categoryorder':'total ascending'}
)
fig.show("png");
# создадим сводную таблицу с круглосуточными кофейнями для вывода на карту Москвы
coff_for_map = df_coff.query('is_24_7 == True')
coff_for_map = coff_for_map.groupby(
['name', 'lat', 'lng']
).agg({'chain' : 'count', 'rating' : 'median'})
coff_for_map = coff_for_map.reset_index()
coff_for_map = coff_for_map.rename(columns={'chain':'count'})
# создаём карту Москвы
m_4 = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём пустой кластер, добавляем его на карту
marker_cluster = MarkerCluster().add_to(m_4)
def create_clusters(row):
# сохраняем URL-адрес изображения со значком с icons8,
# это путь к файлу на сервере icons8
icon_url = 'https://img.icons8.com/?size=160&id=Ztce0zxzCUVT&format=png'
# создаём объект с собственной иконкой размером 30x30
icon = CustomIcon(icon_url, icon_size=(30, 30))
# создаём маркер с иконкой icon и добавляем его в кластер
Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} {row['rating']}",
icon=icon,
).add_to(marker_cluster)
# применяем функцию для создания кластеров к каждой строке датафрейма
coff_for_map.apply(create_clusters, axis=1)
# выводим карту
m_4
- Круглосуточных кофейн в Москве очень мало - 4.2% от общего числа кофейн.
- Большая часть круглосуточных кофейн находятся в Центральном округе, они расположились в доль садового кольца, на ул. Новый Арбат, Большая Никитская и других проходных улицах.
- В остальных районах круглосуточные кофейни большая редкость, чаще всего они распологаются вдоль больших проспектов, вероятно больше расчитаны на таксистов.
- Самый высокий средний рейтинг у кофейн расположенных в Центральном, Восточном и Юго-Западном районах.
- Самый низкий рейтинг у единственной круглосуточной кофейни в Юго-Восточном административном округе.
Вернуться в начало проекта
Анализ рейтингов кофейн и их распределение по районам¶
Посмотрим на рейтинги и распространение по районам вцелом по всем кофейням Москвы.
rating_coff = df_coff.groupby(
'district',
as_index=False
)['rating'].agg('mean').round(2)
rating_coff = rating_coff.sort_values(
by = 'rating',
ascending = False
)
fig = px.bar(
rating_coff,
x='rating',
y='district',
text='rating',
template='plotly_white',
color='rating'
)
# оформляем график
fig.update_layout(
title='Распределение средних рейтингов кофейн по районам Москвы',
width=700,
height=400,
xaxis_title='Средний рейтинг',
yaxis_title='Район Москвы'
)
fig.update_xaxes(range=[4.1, 4.4])
fig.show("png");
- В целом разброс в значениях между средними рейтингами кофейн по районам Москвы не большой между 4.2 и 4.34.
- Самый высокий средний рейтинг у кофейн расположенных в Центральном административном округе - 4.34 пункта и Северо-Западном округе.
- Самый низкий средний рейтинг у кофейн в Западном районе - 4.2
Вернуться в начало проекта
Анализ цен при открытии¶
Выясним на какую стоимость чашки капучино стоит ориентироваться при открытии кофейни.
df_coff.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 1397 entries, 3 to 8396 Data columns (total 18 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 1397 non-null object 1 category 1397 non-null object 2 address 1397 non-null object 3 district 1397 non-null object 4 hours 1382 non-null object 5 lat 1397 non-null float64 6 lng 1397 non-null float64 7 rating 1397 non-null float64 8 price 470 non-null object 9 avg_bill 711 non-null object 10 middle_avg_bill 196 non-null float64 11 middle_coffee_cup 515 non-null float64 12 chain 1397 non-null int64 13 seats 1397 non-null float64 14 street 1367 non-null object 15 is_24_7 1397 non-null bool 16 chain_type 1397 non-null object 17 work_hours_type 1397 non-null object dtypes: bool(1), float64(6), int64(1), object(10) memory usage: 197.8+ KB
Только у 521 кофейни из 1413 в датафрейме заполнены сведения о стоимости чашки капучино, исследуем данные о стоимости чашки капучино по этим кофейням.
price_cof_cup = df_coff.query('middle_coffee_cup > 0')
price_cof_cup['middle_coffee_cup'].describe()
count 515.000000 mean 172.524272 std 65.879982 min 60.000000 25% 124.500000 50% 170.000000 75% 225.000000 max 375.000000 Name: middle_coffee_cup, dtype: float64
В целом по Москве:
- Среднее значение за чашку капучино - 172 руб.
- Медианное значение - 170 руб.
- Максимальное значение 375 руб., а минимальная стоимость чашки капучино - 60 руб.
price_cof_pivot = price_cof_cup.groupby(
'middle_coffee_cup',
as_index=False
)['name'].agg('count')
fig = px.histogram(
price_cof_pivot,
x = 'middle_coffee_cup',
y = 'name',
title = 'Распределение количества заведений по стоимости за чашку кофе',
nbins = 200,
)
fig.update_xaxes(title_text = 'Средняя стоимость чашки капучино')
fig.update_yaxes(title_text = 'Количество заведений')
fig.show("png");
На графике наблюдается скачок в цене в размере 256 руб за чашку капучино, посмотрим, что это за кофейни с одинаковый средним чеком.
df_256 = price_cof_cup.query('middle_coffee_cup == 256')
print(df_256['name'].value_counts())
шоколадница 42 Name: name, dtype: int64
Все 42 кофейни со стоимостью чашки капучино 256 руб - это сетевые кофейни "Шоколадница", где равный средний чек. Для сетевых заведений характерно придерживаться единой ценовой политики на меню.
# Выведем среднюю стоимость чашки капучино по районам
district_cup = df_coff.groupby(
'district',
as_index=False
)['middle_coffee_cup'].agg('mean').round().sort_values(
'middle_coffee_cup',
ascending=False
)
district_cup
| district | middle_coffee_cup | |
|---|---|---|
| 1 | Западный административный округ | 189.0 |
| 5 | Центральный административный округ | 188.0 |
| 7 | Юго-Западный административный округ | 184.0 |
| 2 | Северный административный округ | 166.0 |
| 4 | Северо-Западный административный округ | 166.0 |
| 3 | Северо-Восточный административный округ | 165.0 |
| 8 | Южный административный округ | 158.0 |
| 6 | Юго-Восточный административный округ | 151.0 |
| 0 | Восточный административный округ | 143.0 |
# создаём карту Москвы
m_5 = Map(
location=[moscow_lat, moscow_lng],
zoom_start=10,
tiles='Cartodb Positron'
)
# создаём хороплет с помощью конструктора Choropleth и добавляем его на карту
cup_map = Choropleth(
geo_data = state_geo,
data = district_cup,
columns = ['district', 'middle_coffee_cup'],
key_on = 'feature.name',
fill_color = 'YlOrBr',
legend_name = 'Средняя цена чашки кофе по районам Москвы',
).add_to(m_5)
#добавим подписи административным округам при наведении курсора на них
cup_map.geojson.add_child(
folium.features.GeoJsonTooltip(['name',], labels=False)
)
# выводим карту
m_5
- Средняя цена за чашку капучино по Москве колеблется по районам в пределах от 143 руб. до 189 руб.
- Самые высокие цены на капучино в Западном (189 руб.), Центральном (188 руб.) и Юго-Западном (184 руб.) округах.
- Самые низкие цены на чашку капучино в Восточном -143 руб., Юго-Восточном округе - 151 руб и и Южном административном округе - 158 руб.
При открытии кафе стоит ориентироваться на среднюю стоимость чашечки капучино внутри того округа где планируется открывать кофейню, потому что чашка капучино это как маячок для посетителей кофейни, если будет завышена цена, то это может создать впечатление что в заведении слишком высокие цены и средний посетитель не будет заходить к вам в заведение. Если сделать слишком низкую цену на капучино, то это может быть сигналом о том что в данном заведении подают некачественный кофе, и будет предвзятое отношение.
Вернуться в начало проекта
Топ-10 сетевых кофейн¶
Рассмотрим какое количество сетевых кофейн среди остальных по Москве. Изучим топ-10 сетевых кофейн по параметрам - посадки, рейтинга, ценовой категории.
chain_coff = df_coff.groupby(
'chain_type',
as_index = False
)['name'].agg('count')
chain_coff['share'] = round(
chain_coff['name'] / chain_coff['name'].sum() *100
)
chain_coff
| chain_type | name | share | |
|---|---|---|---|
| 0 | несетевое | 686 | 49.0 |
| 1 | сетевое | 711 | 51.0 |
# Отразим на круговой диаграмме доли сетевых кофейн
fig = px.pie(
chain_coff,
values='name',
names='chain_type'
)
fig.update_layout(
title='Доля сетевых кофейн Москвы',
width=700,
height=400,
annotations=[dict(
x=1.15,
y=1.05,
text='Категория',
showarrow=False
)]
)
fig.show("png");
# уберем 1% аномальных значений посадочных мест
df_coff = df_coff[~(df_coff['seats'] > np.nanpercentile(df_coff['seats'], 99))]
#выделим сетевые заведения в отдельный датафрейм
chain_coffe_hous = df_coff.query('chain == 1')
# выведем на экран топ-15 сетевых заведений по количественному признаку
top_10_coffe = chain_coffe_hous.groupby(['name']).agg({
'chain' : 'count',
'rating' : 'mean',
'seats' : 'median',
'price' : 'first'
})
# переименуем столбец
top_10_coffe = top_10_coffe.rename(columns={'chain':'count'})
# округлим значение рейтинга до 1 значения после запятой
top_10_coffe['rating'] = round(top_10_coffe['rating'], 1)
# отсортируем по убыванию и оставим только 10 наименований заведений
top_10_coffe = top_10_coffe.sort_values(
'count',
ascending = False
).reset_index().head(10)
top_10_coffe
| name | count | rating | seats | price | |
|---|---|---|---|---|---|
| 0 | шоколадница | 116 | 4.2 | 61.5 | средние |
| 1 | one price coffee | 69 | 4.1 | 64.0 | средние |
| 2 | cofix | 64 | 4.1 | 14.0 | средние |
| 3 | кофепорт | 40 | 4.2 | 40.5 | низкие |
| 4 | cofefest | 31 | 4.0 | 0.0 | средние |
| 5 | кофемания | 21 | 4.5 | 80.0 | высокие |
| 6 | cinnabon | 19 | 3.9 | 45.0 | низкие |
| 7 | правда кофе | 12 | 4.3 | 0.0 | низкие |
| 8 | krispy kreme | 9 | 4.2 | 98.0 | средние |
| 9 | даблби | 8 | 4.3 | 57.0 | средние |
# Выведем частоту ценовых категорий по всем кофейням
df_coff['price'].value_counts()
средние 368 низкие 66 высокие 17 выше среднего 14 Name: price, dtype: int64
# У "wild bean cafe" не указана ценовая категория, не будем ее выводить на график
top_10_coffe = top_10_coffe.query('name != "wild bean cafe"')
# Построим столбчатый график распределения ценовой категории кофейн топ-10
fig = px.bar(
top_10_coffe,
x='count',
y='name',
text='count',
template='plotly_white',
color='price'
)
# оформляем график
fig.update_layout(
title='Распределения кофейн топ-10 по ценовым категориям',
width=700,
height=400,
xaxis_title='Количество кофейн',
yaxis_title='Название кофейни'
)
#fig.update_xaxes(range=[4.1, 4.4])
fig.show("png");
- Сетевых кофейн 51% от общего числа кофен, что говорит о популярности сетевых кофейн.
- Среди сетевых кофейн в топ-10 по количеству попали: Шоколадница; Оne price coffee; Сofix; Кофепорт; Сofefest; Кофемания; Сinnabon; Правда кофе; Кrispy kreme; Сoffeekaldi's.
- Большее количество кофейн у Шоколадницы, при этом цены средние.
- Самые высокие рейтинги у Кофемании, но и цены у этих кофейн тоже высокие.
- Среди кофейн основная ценовая категория - средняя.
- Средний показатель посадки у кофейн встречается разный, бывает и ноль (которые работают по системе кофе с собой) так и 98 единиц.
Вернуться в начало проекта
Проверим корреляцию между некоторыми параметрами кофейн¶
# Построим график распределения рейтинга и количества посадочных мест
#plt.figure(figsize=(18, 9))
sns.jointplot(x = 'seats', y = 'rating', data = df_coff, kind = 'reg')
plt.title('Зависимоть между рейтингом и количеством посадочных мест')
plt.xlabel('Количество посадочных мест')
plt.ylabel('Рейтинг')
plt.show();
print('Коэффициент корреляции:', round(df_coff['rating'].corr(df_coff['seats']), 2))
Коэффициент корреляции: -0.02
Коэффициент корреляции -0.02 ничтожно мал, зависимости как таковой нет.
Проверим есть ли зависимость между рейтингом и стоимостью чашки капучино.
# Построим график распределения рейтинга и стоимости чашки капучино
#plt.figure(figsize=(18, 9))
sns.jointplot(x = 'middle_coffee_cup', y = 'rating', data = price_cof_cup, kind = 'reg')
plt.title('Зависимоть между рейтингом и стоимостью чашки капучино')
plt.xlabel('Стоимость чашки капучино')
plt.ylabel('Рейтинг')
plt.show();
print('Коэффициент корреляции:', round(
price_cof_cup['rating'].corr(price_cof_cup['middle_coffee_cup']),
2
))
Коэффициент корреляции: 0.14
Коэффициент корреляции очень маленький 0.16, говорит о том что зависимости между рейтингом и стоимостью чашки капучино нет.
Посмотрим на коэффициент корреляции между количеством посадочных и стоимостью чашки капучино.
# Построим график распределения количества посадочных мест и стоимости чашки капучино
#plt.figure(figsize=(18, 9))
sns.jointplot(x = 'middle_coffee_cup', y = 'seats', data = price_cof_cup, kind = 'reg')
plt.title('Зависимоть между количеством посадочных мест и стоимостью чашки капучино')
plt.xlabel('Стоимость чашки капучино')
plt.ylabel('Количество посадочных мест')
plt.show();
print('Коэффициент корреляции:', round(
price_cof_cup['seats'].corr(price_cof_cup['middle_coffee_cup']),
2
))
Коэффициент корреляции: 0.01
Все поверенные корреляции оказались маленькими и незначительными, это говорит о том что такие показатели как рейтинг и количество посадочных мест не влияют на цены в кофейнях Москвы. Вероятнее всего на ценообразование в кофейнях влияют другие параметры, которые мы не можем проверить в рамках данного проекта.
Вернуться в начало проекта
ТОП-15 улиц с самой высокой средней ценой чашки кофе и с самыми высокими средними рейтингами¶
# в сводной таблице посчитаем количество заведений по каждой улице
street_top = df.pivot_table(
index='street',
values=['middle_coffee_cup', 'rating'],
aggfunc={'middle_coffee_cup' : 'mean', 'rating' : 'mean'}
).sort_values(by=['middle_coffee_cup', 'rating'], ascending=False).head(15)
# сформируем список с наименованием улиц
street_top_cup = street_top.index
street_top = street_top.reset_index()
print('Топ-15 улиц по самому высокому среднему чеку и рейтингу:')
display(street_top)
Топ-15 улиц по самому высокому среднему чеку и рейтингу:
| street | middle_coffee_cup | rating | |
|---|---|---|---|
| 0 | большая никитская улица | 328.0 | 4.564286 |
| 1 | 3-я фрунзенская улица | 320.0 | 4.300000 |
| 2 | богословский переулок | 300.0 | 4.600000 |
| 3 | большая сухаревская площадь | 300.0 | 4.375000 |
| 4 | площадь победы | 291.0 | 4.383333 |
| 5 | улица гарибальди | 291.0 | 4.331250 |
| 6 | 3-й крутицкий переулок | 291.0 | 4.260000 |
| 7 | милютинский переулок | 290.0 | 4.450000 |
| 8 | енисейская улица | 287.0 | 4.326667 |
| 9 | стремянный переулок | 285.0 | 4.477778 |
| 10 | мясницкая улица | 283.0 | 4.424000 |
| 11 | улица 1812 года | 275.0 | 4.566667 |
| 12 | спиридоньевский переулок | 275.0 | 4.550000 |
| 13 | улица охотный ряд | 275.0 | 4.400000 |
| 14 | улица серпуховский вал | 275.0 | 4.344444 |
# Построим график распределения средней стоимости капучино по топ-15 улицам Москвы
fig = px.bar(
street_top.sort_values(
by=['middle_coffee_cup', 'rating'],
ascending=False
),
x='middle_coffee_cup',
y= street_top_cup,
text='middle_coffee_cup',
color='rating',
)
# оформляем график
fig.update_layout(
title='Распределение средней стоимости капучино по топ-15 улицам Москвы',
width=700,
height=450,
xaxis_title='Средняя цена чашки кофе',
yaxis_title='Название улицы',
yaxis={'categoryorder':'total ascending'}
)
fig.update_xaxes(range=[260, 340])
fig.show("png");
В топ-15 улиц с самой высокой средней стоимостью чашки кофе вошли следующие улицы Москвы:
- Большая Никитская улица;
- 3-я Фрунзенская улица;
- Богословский переулок;
- Большая Сухаревская площадь;
- площадь Победы;
- улица Гарибальди;
- 3-й Крутицкий переулок;
- Милютинский переулок;
- Енисейская улица;
- Стремянный переулок;
- Мясницкая улица;
- улица 1812 года;
- Спиридоньевский переулок;
- улица Охотный ряд;
- улица Серпуховский вал.
Большая часть улиц из этого списка находится в центральном районе Москвы в пределах Садового кольца.
Вернуться в начало проекта
Вывод¶
В ходе детализированного исследования кофейн Москвы было выявлено:
- Всего представлено 1 413 кофейн.
- Больше всего кофейн в Центральном районе Москвы, их количество превышает более чем в два раза над остальными районами. Это говорит о высокой конкуренции в данном районе, его не стоит рассматривать для открытия кофейни.
- Меньше всего кофейн в Северо-Западном административном округе. Это перспективное направление для развития.
- Доля круглосуточных кофейн в Москве составляет 4.2% от общего числа кофейн. Это перспективное направление для развития.
- Большая часть круглосуточных кофейн находятся в Центральном округе, они расположились в доль садового кольца, на ул. Новый Арбат, Большая Никитская и других проходных улицах.
- В остальных районах круглосуточные кофейни большая редкость, чаще всего они распологаются вдоль больших проспектов.
- В целом разброс в значениях между средними рейтингами кофейн по районам Москвы не большой между 4.2 и 4.34.
При открытии кафе стоит ориентироваться на среднюю стоимость чашки капучино внутри того округа где планируется открывать кофейню, потому что чашка капучино это как маячок для посетителей кофейни, если будет завышена цена, то это может создать впечатление что в заведении слишком высокие цены и средний посетитель не будет заходить к вам в заведение. Если сделать слишком низкую цену на капучино, то это может быть сигналом о том что в данном заведении подают некачественный кофе, и будет предвзятое отношение. Средняя цена за чашку капучино по Москве колеблется по районам в пределах от 151 руб. до 190 руб., так самые высокие цены на капучино в Западном (190 руб.), Центральном (188 руб.) и Юго-Западном (184 руб.) округах; а самые низкие цены на чашку капучино в Юго-Восточном округе - 151 руб и и Южном административном округе - 158 руб.
- В Москве большой популярностью пользуются сетевые кофейни их доля составляет 51% от общего числа кофен.
- Среди сетевых кофейн в топ-10 по количеству попали: Шоколадница; Оne price coffee; Сofix; Кофепорт; Сofefest; Кофемания; Сinnabon; Правда кофе; Кrispy kreme; Сoffeekaldi's.
- Большее количество кофейн у Шоколадницы, при этом цены у этой сети средние.
- Самые высокие рейтинги у Кофемании, но и цены у этих кофейн тоже высокие.
- Среди кофейн основная ценовая категория - средняя.
- Средний показатель посадки у кофейн встречается разный, бывает и ноль (которые работают по системе кофе с собой) так и 98 единиц.
- Взаимосвязи между типами цен, ценой чашки кофе и показателями рейтинга, количества посадочных мест не выявлено.
- В топ-15 улиц с самой высокой средней стоимостью чашки кофе вошли следующие улицы Москвы:
- Большая Никитская улица;
- 3-я Фрунзенская улица;
- Богословский переулок;
- Большая Сухаревская площадь;
- площадь Победы;
- улица Гарибальди;
- 3-й Крутицкий переулок;
- Милютинский переулок;
- Енисейская улица;
- Стремянный переулок;
- Мясницкая улица;
- улица 1812 года;
- Спиридоньевский переулок;
- улица Охотный ряд;
- улица Серпуховский вал.
Большая часть улиц из этого списка находится в центральном районе Москвы в пределах Садового кольца.
Рекомендации:
Если не боятся конкуренции, то можно открывать кофейню в любом из районов, но если есть цель открыть доступную кофейню, то лучше не рассматривать такие районы как Центральный и Западный, вероятнее всего цены на аренду помещений в этих районах завышены и сказываются на ценообразовании. Стоит присмотреться к списку топ-15 улиц с самой высокой средней ценой чашки кофе и с самыми высокими средними рейтингами.
Стоит открыть сеть качественных круглосуточных кофейн со средней стоимостью чашки капучино приравненной к средней стоимости чашки капучино в том районе где планируется открытие кофейни.
Лучше всего распологать кофейни в проходимых местах недалеко от метро, бизнес центров, высших учебных заведений или студенческих общежитий.
Вернуться в начало проекта
Итоговый вывод по проекту¶
В ходе работы над проектом были:
Загружены и предобработанны данные о заведениях общественного питания Москвы, составленные на основе сервисов Яндекс Карты и Яндекс Бизнес на лето 2022 года.
Проведен исследовательский анализ данных, на данном этапе выявлено что:
Структура рынка: преобладают кафе (28,3%) и рестораны (24,3%), третье место занимают кофейни (16,8%). Реже встречаются пекарни и столовые.
Вместимость: Большинство заведений имеют от 0 до 100 мест. Кафе, пекарни, столовые, фаст-фуды и кофейни обычно имеют 4–8 средних мест и 46–55 средних мест.
Сетевые и несетевые заведения: 62% не являются участниками сети. Кофейни, пиццерии и пекарни имеют больше сетевых заведений. Сетевые заведения обычно располагаются вблизи мест с интенсивным движением и высокой проходимостью (метро, торговые центры, бизнес-центры, парки).
Географическое расположение: В Центральном районе самая высокая концентрация заведений, особенно кофеен, ресторанов и кафе. В других округах распределение категорий заведений и их количество более равномерное между районами.
Рейтинги: Средний рейтинг варьируется от 4,0 до 4,4 по категориям, и не имеет большого разброса в пунктах не по территориальному принципу, не по ценовому не по категориальному. Бары/пабы лидируют с показателем 4,39.
Ценовая категория: Самый высокий средний чек — в Центральном и Западном административных округах (около 1000 рублей), в остальных округах — меньший.
Круглосуточные заведения: они составляют 8,7% всех заведений, причем наиболее распространенными в этой категории являются кафе, фаст-фуды и рестораны.
Заведения с низким рейтингом: чаще всего среди заведений с низкими рейтингами встречаются кафе и фастфуд, реже всего с низким рейтингом можно встретить пиццерию. У заведений с низким рейтингом ниже и средний чек, что логично, ведь снижая цены зачастую снижается качество продуктов и сервиса, зато растет доступность.
- Проведено детализированное исследование открытие кофейни:
- Всего представлено 1 413 кофейн города Москвы.
- Самый высокий показатель количества кофейн в Центральном округе.
- В Северо-Западном округе меньше всего, что указывает на потенциал для новых открытий.
- Круглосуточные кофейни — перспективное направление, преимущественно расположенное в Центральном округе.
- Сетевые кофейни составляют 51% рынка.
- К ведущим сетям относятся «Шоколадница» , «Кофемания » и другие, с разными ценами и рейтингами. Чаще для кофейн характерен средний диапазон цен.
- Не выявлено корреляции между ценой, рейтингом и количеством посадочных мест.
- Цена капучино как показатель качества. Средняя цена варьируется в зависимости от района, самая высокая в Западном, Центральном и Юго-Западном округах.
- Составлен ТОП-15 улиц с самой высокой средней ценой чашки кофе и с самыми высокими средними рейтингами, в который вошли следующие улицы Москвы:
- Большая Никитская улица;
- 3-я Фрунзенская улица;
- Богословский переулок;
- Большая Сухаревская площадь;
- площадь Победы;
- улица Гарибальди;
- 3-й Крутицкий переулок;
- Милютинский переулок;
- Енисейская улица;
- Стремянный переулок;
- Мясницкая улица;
- улица 1812 года;
- Спиридоньевский переулок;
- улица Охотный ряд;
- улица Серпуховский вал.
На основе комплексного аналитического отчета о городских кофейн Москвы рекомендации для инвестора, желающего открыть новую сеть городских кофеен:
Выбор местоположения: Рассмотрите Северо-Западный административный округ из-за более низкой конкуренции и неиспользованного рыночного потенциала.
24-часовая модель: изучите возможность открытия круглосуточного кафе, особенно за пределами Центрального района.
Сетевая или независимая кофейня: взвесьте преимущества присоединения к сети по сравнению с открытием независимой кофейни, учитывая высокую распространенность сетей.
Стратегия ценообразования: привести цену чашки капучино в соответствие со средней ценой по району, чтобы сбалансировать восприятие качества и доступности.
Места и услуги: Рассмотрите сочетание количества мест и, возможно, модель кофе с собой, исходя из местных предпочтений и существующей конкуренции. Стоит пресмотреться к улицам вошедших в топ-15 по самой высокой средней стоимостью чашки кофе и средниму рейтингу. Большая часть улиц из этого списка находится в центральном районе Москвы в пределах Садового кольца.
Сосредоточив внимание на этих областях, инвестор сможет стратегически позиционировать новую сеть кофеен для достижения успеха на конкурентном рынке городских кофеен Москвы.
ПРЕЗЕНТАЦИЯ: https://disk.yandex.ru/d/Kifj9kFiAc9pYQ
Вернуться в начало проекта